Skip to content

Commit

Permalink
Fixed #19210 -- Handling of leap years in django.utils.timesince
Browse files Browse the repository at this point in the history
django.utils.timesince used to ignore leap years which lead to big
inaccuracies as soon as you used it on big time spans. This is the
most simple fix for this bug, as explained in the ticket.
  • Loading branch information
raphaelm committed Jun 4, 2015
1 parent 57dbc87 commit e392f7e
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 0 deletions.
5 changes: 5 additions & 0 deletions django/utils/timesince.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals

import calendar
import datetime

from django.utils.html import avoid_wrapping
Expand Down Expand Up @@ -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
delta -= datetime.timedelta(calendar.leapdays(d.year, now.year))

# ignore microseconds
since = delta.days * 24 * 60 * 60 + delta.seconds
if since <= 0:
Expand Down
3 changes: 3 additions & 0 deletions docs/releases/1.9.txt
Expand Up @@ -285,6 +285,9 @@ Templates
the ability to register libraries and builtins explicitly through the
template :setting:`OPTIONS <TEMPLATES-OPTIONS>`.

* The ``timesince`` and ``timeuntil`` filters were improved to deal with leap
years when given large time spans.

Requests and Responses
^^^^^^^^^^^^^^^^^^^^^^

Expand Down
5 changes: 5 additions & 0 deletions tests/utils_tests/test_timesince.py
Expand Up @@ -131,3 +131,8 @@ def utcoffset(self, dt):
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):
now = datetime.datetime.now()
t = datetime.datetime(1007, 8, 14, 13, 46, 0)
self.assertEqual(timesince(t, self.t), '1000\xa0years')

0 comments on commit e392f7e

Please sign in to comment.