Index: django/contrib/sessions/middleware.py
===================================================================
--- django/contrib/sessions/middleware.py	(revision 6594)
+++ django/contrib/sessions/middleware.py	(working copy)
@@ -25,17 +25,15 @@
             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
-                    rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
-
+                    max_age = request.session.get_max_age()
+                    expiry_date = request.session.get_expiry_date()
                     # Fixed length date must have '-' separation in the format
                     # DD-MMM-YYYY for compliance with Netscape cookie standard
-                    expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
-                              datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
+                    expires = expiry_date.strftime('%a, %d-%b-%Y %H:%M:%S GMT')
 
                 # Save the seesion data and refresh the client cookie.
                 request.session.save()
Index: django/contrib/sessions/tests.py
===================================================================
--- django/contrib/sessions/tests.py	(revision 6594)
+++ django/contrib/sessions/tests.py	(working copy)
@@ -75,6 +75,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 6594)
+++ 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
 
@@ -120,6 +121,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: AUTHORS
===================================================================
--- AUTHORS	(revision 6594)
+++ AUTHORS	(working copy)
@@ -311,7 +311,7 @@
     tstromberg@google.com
     Makoto Tsuyuki <mtsuyuki@gmail.com>
     tt@gurgle.no
-    Amit Upadhyay
+    Amit Upadhyay <http://www.amitu.com/blog/>
     Geert Vanderkelen
     viestards.lists@gmail.com
     George Vilches <gav@thataddress.com>
Index: docs/sessions.txt
===================================================================
--- docs/sessions.txt	(revision 6594)
+++ docs/sessions.txt	(working copy)
@@ -80,42 +80,81 @@
 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()``
 
     * ``items()``
 
-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)``
+
+      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.
+
+      If ``value`` is ``None``, the session reverts to using the global session
+      expiry policy.
+
+    * ``get_max_age()``
+
+      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()``
+
+      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()``
+
+      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.
 
@@ -276,6 +315,10 @@
 her browser. Use this if you want people to have to log in every time they open
 a browser.
 
+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
 ==========================
 
