diff --git a/django/utils/timesince.py b/django/utils/timesince.py index b4ae61e4d9d..06accab2e04 100644 --- a/django/utils/timesince.py +++ b/django/utils/timesince.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals +import calendar import datetime from django.utils.html import avoid_wrapping @@ -40,6 +41,10 @@ def timesince(d, now=None, reversed=False): now = datetime.datetime.now(utc if is_aware(d) else None) delta = (d - now) if reversed else (now - d) + + # Deal with leapyears by subtracing the number of leapdays + delta -= datetime.timedelta(calendar.leapdays(d.year, now.year)) + # ignore microseconds since = delta.days * 24 * 60 * 60 + delta.seconds if since <= 0: diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index ecd2af6ddc6..e06946aaa65 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -297,6 +297,9 @@ Templates the ability to register libraries and builtins explicitly through the template :setting:`OPTIONS `. +* The ``timesince`` and ``timeuntil`` filters were improved to deal with leap + years when given large time spans. + Requests and Responses ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/utils_tests/test_timesince.py b/tests/utils_tests/test_timesince.py index 90d33d00f74..ea1064f902e 100644 --- a/tests/utils_tests/test_timesince.py +++ b/tests/utils_tests/test_timesince.py @@ -131,3 +131,7 @@ class TimesinceTests(unittest.TestCase): self.assertEqual(timesince(future), '0\xa0minutes') past = datetime.datetime(1980, 1, 1, tzinfo=naive()) self.assertEqual(timeuntil(past), '0\xa0minutes') + + def test_thousand_years_ago(self): + t = datetime.datetime(1007, 8, 14, 13, 46, 0) + self.assertEqual(timesince(t, self.t), '1000\xa0years')