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, 
+                session_key = self.session_key,
                 expire_date__gt=datetime.datetime.now()
             )
             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,7 +106,7 @@
 
     * ``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
@@ -118,6 +123,45 @@
     * ``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
+      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 +322,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
 ==========================
 
