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

This commit is contained in:
Aymeric Augustin 2012-07-19 23:02:22 +02:00
parent 123362dd37
commit 5d560dcb98
2 changed files with 52 additions and 26 deletions

View File

@ -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 File

@ -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 @@ class HumanizeTests(TestCase):
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 @@ class HumanizeTests(TestCase):
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 @@ class HumanizeTests(TestCase):
'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',
]
# 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'
# 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
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