Index: django/contrib/sessions/middleware.py
===================================================================
--- django/contrib/sessions/middleware.py	(revision 6980)
+++ django/contrib/sessions/middleware.py	(working copy)
@@ -26,12 +26,12 @@
             if accessed:
                 patch_vary_headers(response, ('Cookie',))
             if modified or settings.SESSION_SAVE_EVERY_REQUEST:
-                if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
+                if request.session.get_expire_at_browser_close():
                     max_age = None
                     expires = None
                 else:
-                    max_age = settings.SESSION_COOKIE_AGE
-                    expires_time = time.time() + settings.SESSION_COOKIE_AGE
+                    max_age = request.session.get_max_age()
+                    expires_time = time.time() + max_age
                     expires = cookie_date(expires_time)
                 # Save the seesion data and refresh the client cookie.
                 request.session.save()
Index: django/contrib/sessions/tests.py
===================================================================
--- django/contrib/sessions/tests.py	(revision 6980)
+++ django/contrib/sessions/tests.py	(working copy)
@@ -88,6 +88,100 @@
 
 >>> s.pop('some key', 'does not exist')
 'does not exist'
+
+#########################
+# Custom session expiry #
+#########################
+
+>>> from django.conf import settings
+>>> from datetime import datetime, timedelta
+
+>>> td10 = timedelta(seconds=10)
+
+# A normal session has a max age equal to settings 
+>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
+True
+
+# So does a custom session with an idle expiration time of 0 (but it'll expire
+# at browser close)
+>>> s.set_expiry(0)
+>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
+True
+
+# Custom session idle expiration time
+>>> s.set_expiry(10)
+>>> delta = s.get_expiry_date() - datetime.utcnow()
+>>> delta.seconds in (9, 10)
+True
+>>> age = s.get_max_age()
+>>> age in (9, 10)
+True
+
+# Custom session fixed expiry date (timedelta)
+>>> s.set_expiry(td10)
+>>> delta = s.get_expiry_date() - datetime.utcnow()
+>>> delta.seconds in (9, 10)
+True
+>>> age = s.get_max_age()
+>>> age in (9, 10)
+True
+
+# Custom session fixed expiry date (fixed datetime)
+>>> s.set_expiry(datetime.utcnow() + td10)
+>>> delta = s.get_expiry_date() - datetime.utcnow()
+>>> delta.seconds in (9, 10)
+True
+>>> age = s.get_max_age()
+>>> age in (9, 10)
+True
+
+# Set back to default session age
+>>> s.set_expiry(None)
+>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
+True
+
+# Allow to set back to default session age even if no alternate has been set
+>>> s.set_expiry(None)
+
+
+# We're changing the setting then reverting back to the original setting at the
+# end of these tests.
+>>> original_expire_at_browser_close = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False
+
+# Custom session age
+>>> s.set_expiry(10)
+>>> s.get_expire_at_browser_close()
+False
+
+# Custom expire-at-browser-close
+>>> s.set_expiry(0)
+>>> s.get_expire_at_browser_close()
+True
+
+# Default session age
+>>> s.set_expiry(None)
+>>> s.get_expire_at_browser_close()
+False
+
+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = True
+
+# Custom session age
+>>> s.set_expiry(10)
+>>> s.get_expire_at_browser_close()
+False
+
+# Custom expire-at-browser-close
+>>> s.set_expiry(0)
+>>> s.get_expire_at_browser_close()
+True
+
+# Default session age
+>>> s.set_expiry(None)
+>>> s.get_expire_at_browser_close()
+True
+
+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = original_expire_at_browser_close
 """
 
 if __name__ == '__main__':
Index: django/contrib/sessions/backends/base.py
===================================================================
--- django/contrib/sessions/backends/base.py	(revision 6980)
+++ django/contrib/sessions/backends/base.py	(working copy)
@@ -4,6 +4,7 @@
 import random
 import sys
 import time
+from datetime import datetime, timedelta
 from django.conf import settings
 from django.core.exceptions import SuspiciousOperation
 
@@ -128,6 +129,54 @@
 
     _session = property(_get_session)
 
+    def get_max_age(self):
+        expiry = self.get('_session_expiry')
+        if not expiry:   # Checks both None and 0 cases
+            return settings.SESSION_COOKIE_AGE
+        if not isinstance(expiry, datetime):
+            return expiry
+        delta = expiry - datetime.utcnow()
+        return delta.days * 86400 + delta.seconds
+
+    def get_expiry_date(self):
+        "Returns the expiry date (in UTC)"
+        expiry = self.get('_session_expiry', settings.SESSION_COOKIE_AGE)
+        if isinstance(expiry, datetime):
+            return expiry
+        return datetime.utcnow() + timedelta(seconds=expiry)
+
+    def set_expiry(self, value):
+        """
+        Sets a custom expiration for the session. ``value`` can be an integer, a
+        Python ``datetime`` or ``timedelta`` object or ``None``.
+
+        If ``value`` is an integer, the session will expire after that many
+        seconds of inactivity. If set to ``0`` then the session will expire on
+        browser close.
+
+        If ``value`` is a ``datetime`` or ``timedelta`` object, the session
+        will expire at that specific future time (``datetime`` objects should be
+        UTC).
+
+        If ``value`` is ``None``, the session uses the global session expiry
+        policy.
+        """
+        if value is None:
+            # Remove any custom expiration for this session.
+            try:
+                del self['_session_expiry']
+            except KeyError:
+                pass
+            return
+        if isinstance(value, timedelta):
+            value = datetime.utcnow() + value
+        self['_session_expiry'] = value
+
+    def get_expire_at_browser_close(self):
+        if self.get('_session_expiry') is None:
+            return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
+        return self.get('_session_expiry') == 0
+
     # Methods that child classes must implement.
 
     def exists(self, session_key):
Index: django/contrib/sessions/backends/cache.py
===================================================================
--- django/contrib/sessions/backends/cache.py	(revision 6980)
+++ django/contrib/sessions/backends/cache.py	(working copy)
@@ -4,23 +4,23 @@
 
 class SessionStore(SessionBase):
     """
-    A cache-based session store. 
+    A cache-based session store.
     """
     def __init__(self, session_key=None):
         self._cache = cache
         super(SessionStore, self).__init__(session_key)
-        
+
     def load(self):
         session_data = self._cache.get(self.session_key)
         return session_data or {}
 
     def save(self):
-        self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE)
+        self._cache.set(self.session_key, self._session, self.get_max_age())
 
     def exists(self, session_key):
         if self._cache.get(session_key):
             return True
         return False
-        
+
     def delete(self, session_key):
         self._cache.delete(session_key)
\ No newline at end of file
Index: django/contrib/sessions/backends/db.py
===================================================================
--- django/contrib/sessions/backends/db.py	(revision 6980)
+++ django/contrib/sessions/backends/db.py	(working copy)
@@ -10,16 +10,16 @@
     """
     def __init__(self, session_key=None):
         super(SessionStore, self).__init__(session_key)
-    
+
     def load(self):
         try:
             s = Session.objects.get(
-                session_key = self.session_key, 
-                expire_date__gt=datetime.datetime.now()
+                session_key = self.session_key,
+                expire_date__gt=datetime.datetime.utcnow()
             )
             return self.decode(s.session_data)
         except (Session.DoesNotExist, SuspiciousOperation):
-            
+
             # Create a new session_key for extra security.
             self.session_key = self._get_new_session_key()
             self._session_cache = {}
@@ -27,21 +27,21 @@
             # Save immediately to minimize collision
             self.save()
             return {}
-            
+
     def exists(self, session_key):
         try:
             Session.objects.get(session_key=session_key)
         except Session.DoesNotExist:
             return False
         return True
-            
+
     def save(self):
         Session.objects.create(
             session_key = self.session_key,
             session_data = self.encode(self._session),
-            expire_date = datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)
+            expire_date = self.get_expiry_date()
         )
-    
+
     def delete(self, session_key):
         try:
             Session.objects.get(session_key=session_key).delete()
Index: AUTHORS
===================================================================
--- AUTHORS	(revision 6980)
+++ AUTHORS	(working copy)
@@ -327,7 +327,7 @@
     tstromberg@google.com
     Makoto Tsuyuki <mtsuyuki@gmail.com>
     tt@gurgle.no
-    Amit Upadhyay
+    Amit Upadhyay <http://www.amitu.com/blog/>
     Geert Vanderkelen
     I.S. van Oostveen <v.oostveen@idca.nl>
     viestards.lists@gmail.com
Index: docs/sessions.txt
===================================================================
--- docs/sessions.txt	(revision 6980)
+++ docs/sessions.txt	(working copy)
@@ -80,19 +80,24 @@
 It implements the following standard dictionary methods:
 
     * ``__getitem__(key)``
+
       Example: ``fav_color = request.session['fav_color']``
 
     * ``__setitem__(key, value)``
+
       Example: ``request.session['fav_color'] = 'blue'``
 
     * ``__delitem__(key)``
+
       Example: ``del request.session['fav_color']``. This raises ``KeyError``
       if the given ``key`` isn't already in the session.
 
     * ``__contains__(key)``
+
       Example: ``'fav_color' in request.session``
 
     * ``get(key, default=None)``
+
       Example: ``fav_color = request.session.get('fav_color', 'red')``
 
     * ``keys()``
@@ -101,23 +106,65 @@
 
     * ``setdefault()`` (**New in Django development version**)
 
-It also has these three methods:
+It also has these methods:
 
     * ``set_test_cookie()``
+
       Sets a test cookie to determine whether the user's browser supports
       cookies. Due to the way cookies work, you won't be able to test this
       until the user's next page request. See "Setting test cookies" below for
       more information.
 
     * ``test_cookie_worked()``
+
       Returns either ``True`` or ``False``, depending on whether the user's
       browser accepted the test cookie. Due to the way cookies work, you'll
       have to call ``set_test_cookie()`` on a previous, separate page request.
       See "Setting test cookies" below for more information.
 
     * ``delete_test_cookie()``
+
       Deletes the test cookie. Use this to clean up after yourself.
 
+    * ``set_expiry(value)``
+
+      **New in Django development version**
+
+      Sets a custom expiration for the session.
+
+      If ``value`` is an integer, the session will expire after that many
+      seconds of inactivity. If set to ``0`` then the session will expire when
+      the user's browser is closed.
+
+      If ``value`` is a ``datetime`` or ``timedelta`` object, the session will
+      expire at that specific time (``datetime`` objects must be in UTC).
+
+      If ``value`` is ``None``, the session reverts to using the global session
+      expiry policy.
+
+    * ``get_max_age()``
+
+      **New in Django development version**
+
+      Returns the number of seconds until this session expires. For sessions
+      with no custom expiration (or those set to expire at browser close), this
+      will equal ``settings.SESSION_COOKIE_AGE``.
+
+    * ``get_expiry_date()``
+
+      **New in Django development version**
+
+      Returns the date this session will expire. For sessions with no custom
+      expiration (or those set to expire at browser close), this will equal the
+      UTC date ``settings.SESSION_COOKIE_AGE`` seconds from now.
+
+    * ``get_expire_at_browser_close()``
+
+      **New in Django development version**
+
+      Returns either ``True`` or ``False``, depending on whether this session
+      will expire when the user's browser is closed.
+
 You can edit ``request.session`` at any point in your view. You can edit it
 multiple times.
 
@@ -278,6 +325,12 @@
 her browser. Use this if you want people to have to log in every time they open
 a browser.
 
+**New in Django development version**
+
+This setting is a global default and can be overwritten by explicitly calling
+``request.session.set_expiry()`` as described above in
+`using sessions in views`_.
+
 Clearing the session table
 ==========================
 
