diff --git a/django/templatetags/cache.py b/django/templatetags/cache.py
index 4436b15d6e..07bd590fba 100644
--- a/django/templatetags/cache.py
+++ b/django/templatetags/cache.py
@@ -1,4 +1,4 @@
-from django.template import Library, Node, TemplateSyntaxError
+from django.template import Library, Node, TemplateSyntaxError, Variable, VariableDoesNotExist
 from django.template import resolve_variable
 from django.core.cache import cache
 from django.utils.encoding import force_unicode
@@ -6,20 +6,27 @@ from django.utils.encoding import force_unicode
 register = Library()
 
 class CacheNode(Node):
-    def __init__(self, nodelist, expire_time, fragment_name, vary_on):
+    def __init__(self, nodelist, expire_time_var, fragment_name, vary_on):
         self.nodelist = nodelist
-        self.expire_time = expire_time
+        self.expire_time_var = Variable(expire_time_var)
         self.fragment_name = fragment_name
         self.vary_on = vary_on
 
     def render(self, context):
+        try:
+            expire_time = self.expire_time_var.resolve(context)
+        except VariableDoesNotExist:
+            raise TemplateSyntaxError('"cache" tag got an unknkown variable: %r' % self.expire_time_var.var)
+        try:
+            expire_time = int(expire_time)
+        except (ValueError, TypeError):
+            raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
         # Build a unicode key for this fragment and all vary-on's.
-        cache_key = u':'.join([self.fragment_name] + \
-            [force_unicode(resolve_variable(var, context)) for var in self.vary_on])
+        cache_key = u':'.join([self.fragment_name] + [force_unicode(resolve_variable(var, context)) for var in self.vary_on])
         value = cache.get(cache_key)
         if value is None:
             value = self.nodelist.render(context)
-            cache.set(cache_key, value, self.expire_time)
+            cache.set(cache_key, value, expire_time)
         return value
 
 def do_cache(parser, token):
@@ -48,10 +55,6 @@ def do_cache(parser, token):
     tokens = token.contents.split()
     if len(tokens) < 3:
         raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0])
-    try:
-        expire_time = int(tokens[1])
-    except ValueError:
-        raise TemplateSyntaxError(u"First argument to '%r' must be an integer (got '%s')." % (tokens[0], tokens[1]))
-    return CacheNode(nodelist, expire_time, tokens[2], tokens[3:])
+    return CacheNode(nodelist, tokens[1], tokens[2], tokens[3:])
 
 register.tag('cache', do_cache)
diff --git a/docs/cache.txt b/docs/cache.txt
index e7e1cdd791..3318b2ad4a 100644
--- a/docs/cache.txt
+++ b/docs/cache.txt
@@ -336,6 +336,17 @@ template tag to uniquely identify the cache fragment::
 It's perfectly fine to specify more than one argument to identify the fragment.
 Simply pass as many arguments to ``{% cache %}`` as you need.
 
+The cache timeout can be a template variable, as long as the template variable
+resolves to an integer value. For example, if the template variable
+``my_timeout`` is set to the value ``600``, then the following two examples are
+equivalent::
+
+    {% cache 600 sidebar %} ... {% endcache %}
+    {% cache my_timeout sidebar %} ... {% endcache %}
+
+This feature is useful in avoiding repetition in templates. You can set the
+timeout in a variable, in one place, and just reuse that value.
+
 The low-level cache API
 =======================
 
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index a90392938d..186b8aacb5 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -863,40 +863,46 @@ class Templates(unittest.TestCase):
 
             ### NOW TAG ########################################################
             # Simple case
-            'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
+            'now01': ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)),
 
             # Check parsing of escaped and special characters
-            'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
-        #    'now03' : ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
-        #    'now04' : ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))
+            'now02': ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),
+        #    'now03': ('{% now "j \"n\" Y"%}', {}, str(datetime.now().day) + '"' + str(datetime.now().month) + '"' + str(datetime.now().year)),
+        #    'now04': ('{% now "j \nn\n Y"%}', {}, str(datetime.now().day) + '\n' + str(datetime.now().month) + '\n' + str(datetime.now().year))
 
             ### URL TAG ########################################################
             # Successes
-            'url01' : ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
-            'url02' : ('{% url regressiontests.templates.views.client_action client.id, action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
-            'url03' : ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
-            'url04' : ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
-            'url05' : (u'{% url метка_оператора v %}', {'v': u'Ω'},
-                    '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
+            'url01': ('{% url regressiontests.templates.views.client client.id %}', {'client': {'id': 1}}, '/url_tag/client/1/'),
+            'url02': ('{% url regressiontests.templates.views.client_action client.id, action="update" %}', {'client': {'id': 1}}, '/url_tag/client/1/update/'),
+            'url03': ('{% url regressiontests.templates.views.index %}', {}, '/url_tag/'),
+            'url04': ('{% url named.client client.id %}', {'client': {'id': 1}}, '/url_tag/named-client/1/'),
+            'url05': (u'{% url метка_оператора v %}', {'v': u'Ω'}, '/url_tag/%D0%AE%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4/%CE%A9/'),
 
             # Failures
-            'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
-            'url-fail02' : ('{% url no_such_view %}', {}, ''),
-            'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
+            'url-fail01': ('{% url %}', {}, template.TemplateSyntaxError),
+            'url-fail02': ('{% url no_such_view %}', {}, ''),
+            'url-fail03': ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
 
             ### CACHE TAG ######################################################
-            'cache01' : ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
-            'cache02' : ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
-            'cache03' : ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'),
-            'cache04' : ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'),
-            'cache05' : ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
-            'cache06' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
-            'cache07' : ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 1}, 'cache05'),
+            'cache01': ('{% load cache %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
+            'cache02': ('{% load cache %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
+            'cache03': ('{% load cache %}{% cache 2 test %}cache03{% endcache %}', {}, 'cache03'),
+            'cache04': ('{% load cache %}{% cache 2 test %}cache04{% endcache %}', {}, 'cache03'),
+            'cache05': ('{% load cache %}{% cache 2 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
+            'cache06': ('{% load cache %}{% cache 2 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
+            'cache07': ('{% load cache %}{% cache 2 test foo %}cache07{% endcache %}', {'foo': 1}, 'cache05'),
+
+            # Allow first argument to be a variable.
+            'cache08': ('{% load cache %}{% cache time test foo %}cache08{% endcache %}', {'foo': 2, 'time': 2}, 'cache06'), 
+            'cache09': ('{% load cache %}{% cache time test foo %}cache09{% endcache %}', {'foo': 3, 'time': -1}, 'cache09'), 
+            'cache10': ('{% load cache %}{% cache time test foo %}cache10{% endcache %}', {'foo': 3, 'time': -1}, 'cache10'), 
 
             # Raise exception if we don't have at least 2 args, first one integer.
-            'cache08' : ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
-            'cache09' : ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
-            'cache10' : ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
+            'cache11': ('{% load cache %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
+            'cache12': ('{% load cache %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
+            'cache13': ('{% load cache %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
+            'cache14': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': 'fail'}, template.TemplateSyntaxError), 
+            'cache15': ('{% load cache %}{% cache foo bar %}{% endcache %}', {'foo': []}, template.TemplateSyntaxError), 
 
             ### AUTOESCAPE TAG ##############################################
             'autoescape-tag01': ("{% autoescape off %}hello{% endautoescape %}", {}, "hello"),