Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #18504 -- Computed |naturalday in local time.

  • Loading branch information...
commit 5d560dcb981400451d69a834f7c6a9090f5e5221 1 parent 123362d
@aaugustin aaugustin authored
View
8 django/contrib/humanize/templatetags/humanize.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
import re
-from datetime import date, datetime, timedelta
+from datetime import date, datetime
from django import template
from django.conf import settings
@@ -143,7 +143,9 @@ def apnumber(value):
return value
return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
-@register.filter
+# Perform the comparison in the default time zone when USE_TZ = True
+# (unless a specific time zone has been applied with the |timezone filter).
+@register.filter(expects_localtime=True)
def naturalday(value, arg=None):
"""
For date values that are tomorrow, today or yesterday compared to
@@ -169,6 +171,8 @@ def naturalday(value, arg=None):
return _('yesterday')
return defaultfilters.date(value, arg)
+# This filter doesn't require expects_localtime=True because it deals properly
+# with both naive and aware datetimes. Therefore avoid the cost of conversion.
@register.filter
def naturaltime(value):
"""
View
72 django/contrib/humanize/tests.py
@@ -1,13 +1,31 @@
from __future__ import unicode_literals
import datetime
-import new
+from django.contrib.humanize.templatetags import humanize
from django.template import Template, Context, defaultfilters
from django.test import TestCase
-from django.utils import translation, tzinfo
-from django.utils.translation import ugettext as _
+from django.test.utils import override_settings
from django.utils.html import escape
from django.utils.timezone import utc
+from django.utils import translation
+from django.utils.translation import ugettext as _
+from django.utils import tzinfo
+
+
+# Mock out datetime in some tests so they don't fail occasionally when they
+# run too slow. Use a fixed datetime for datetime.now(). DST change in
+# America/Chicago (the default time zone) happened on March 11th in 2012.
+
+now = datetime.datetime(2012, 3, 9, 22, 30)
+
+class MockDateTime(datetime.datetime):
+ @classmethod
+ def now(self, tz=None):
+ if tz is None or tz.utcoffset(now) is None:
+ return now
+ else:
+ # equals now.replace(tzinfo=utc)
+ return now.replace(tzinfo=tz) + tz.utcoffset(now)
class HumanizeTests(TestCase):
@@ -109,28 +127,36 @@ def test_naturalday(self):
self.humanize_tester(test_list, result_list, 'naturalday')
def test_naturalday_tz(self):
- from django.contrib.humanize.templatetags.humanize import naturalday
-
today = datetime.date.today()
tz_one = tzinfo.FixedOffset(datetime.timedelta(hours=-12))
tz_two = tzinfo.FixedOffset(datetime.timedelta(hours=12))
# Can be today or yesterday
date_one = datetime.datetime(today.year, today.month, today.day, tzinfo=tz_one)
- naturalday_one = naturalday(date_one)
+ naturalday_one = humanize.naturalday(date_one)
# Can be today or tomorrow
date_two = datetime.datetime(today.year, today.month, today.day, tzinfo=tz_two)
- naturalday_two = naturalday(date_two)
+ naturalday_two = humanize.naturalday(date_two)
# As 24h of difference they will never be the same
self.assertNotEqual(naturalday_one, naturalday_two)
+ def test_naturalday_uses_localtime(self):
+ # Regression for #18504
+ # This is 2012-03-08HT19:30:00-06:00 in Ameria/Chicago
+ dt = datetime.datetime(2012, 3, 9, 1, 30, tzinfo=utc)
+
+ orig_humanize_datetime, humanize.datetime = humanize.datetime, MockDateTime
+ try:
+ with override_settings(USE_TZ=True):
+ self.humanize_tester([dt], ['yesterday'], 'naturalday')
+ finally:
+ humanize.datetime = orig_humanize_datetime
+
def test_naturaltime(self):
class naive(datetime.tzinfo):
def utcoffset(self, dt):
return None
- # we're going to mock datetime.datetime, so use a fixed datetime
- now = datetime.datetime(2011, 8, 15, 1, 23)
test_list = [
now,
now - datetime.timedelta(seconds=1),
@@ -148,6 +174,7 @@ def utcoffset(self, dt):
now + datetime.timedelta(hours=1, minutes=30, seconds=30),
now + datetime.timedelta(hours=23, minutes=50, seconds=50),
now + datetime.timedelta(days=1),
+ now + datetime.timedelta(days=2, hours=6),
now + datetime.timedelta(days=500),
now.replace(tzinfo=naive()),
now.replace(tzinfo=utc),
@@ -169,27 +196,22 @@ def utcoffset(self, dt):
'an hour from now',
'23 hours from now',
'1 day from now',
+ '2 days, 6 hours from now',
'1 year, 4 months from now',
'now',
'now',
]
-
- # mock out datetime so these tests don't fail occasionally when the
- # test runs too slow
- class MockDateTime(datetime.datetime):
- @classmethod
- def now(self, tz=None):
- if tz is None or tz.utcoffset(now) is None:
- return now
- else:
- # equals now.replace(tzinfo=utc)
- return now.replace(tzinfo=tz) + tz.utcoffset(now)
-
- from django.contrib.humanize.templatetags import humanize
- orig_humanize_datetime = humanize.datetime
- humanize.datetime = MockDateTime
-
+ # Because of the DST change, 2 days and 6 hours after the chosen
+ # date in naive arithmetic is only 2 days and 5 hours after in
+ # aware arithmetic.
+ result_list_with_tz_support = result_list[:]
+ assert result_list_with_tz_support[-4] == '2 days, 6 hours from now'
+ result_list_with_tz_support[-4] == '2 days, 5 hours from now'
+
+ orig_humanize_datetime, humanize.datetime = humanize.datetime, MockDateTime
try:
self.humanize_tester(test_list, result_list, 'naturaltime')
+ with override_settings(USE_TZ=True):
+ self.humanize_tester(test_list, result_list_with_tz_support, 'naturaltime')
finally:
humanize.datetime = orig_humanize_datetime
Please sign in to comment.
Something went wrong with that request. Please try again.