Commit 5d560dcb authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

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

parent 123362dd
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
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):
    """
+47 −25
Original line number Diff line number Diff line
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',
        ]

        # 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