Commit 3111d7f6 authored by Malcolm Tredinnick's avatar Malcolm Tredinnick
Browse files

Fixed #7201 -- Fixed the timeuntil filter to work correctly with timezone-aware

times. Patch from Jeremy Carbaugh.

This is backwards incompatible in the sense that previously, if you tried to
compare timezone-aware and timezone-naive values, you got an incorrect result.
Now you get an empty string. So your previously incorrect code returns a
different incorrect result.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8579 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 61957df1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ answer newbie questions, and generally made Django that much better:
    Juan Manuel Caicedo <juan.manuel.caicedo@gmail.com>
    Trevor Caira <trevor@caira.com>
    Ricardo Javier Cárdenes Medina <ricardo.cardenes@gmail.com>
    Jeremy Carbaugh <jcarbaugh@gmail.com>
    Graham Carlyle <graham.carlyle@maplecroft.net>
    Antonio Cavedoni <http://cavedoni.com/>
    C8E
+11 −7
Original line number Diff line number Diff line
@@ -646,20 +646,24 @@ def timesince(value, arg=None):
    from django.utils.timesince import timesince
    if not value:
        return u''
    try:
        if arg:
            return timesince(value, arg)
        return timesince(value)
    except (ValueError, TypeError):
        return u''
timesince.is_safe = False

def timeuntil(value, arg=None):
    """Formats a date as the time until that date (i.e. "4 days, 6 hours")."""
    from django.utils.timesince import timesince
    from django.utils.timesince import timeuntil
    from datetime import datetime
    if not value:
        return u''
    if arg:
        return timesince(arg, value)
    return timesince(datetime.now(), value)
    try:
        return timeuntil(value, arg)
    except (ValueError, TypeError):
        return u''
timeuntil.is_safe = False

###################
+11 −11
Original line number Diff line number Diff line
@@ -28,15 +28,12 @@ def timesince(d, now=None):
    # Convert datetime.date to datetime.datetime for comparison
    if d.__class__ is not datetime.datetime:
        d = datetime.datetime(d.year, d.month, d.day)
    if now:
        t = now.timetuple()
    else:
        t = time.localtime()

    if not now:
        if d.tzinfo:
        tz = LocalTimezone(d)
            now = datetime.datetime.now(LocalTimezone(d))
        else:
        tz = None
    now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)
            now = datetime.datetime.now()

    # ignore microsecond part of 'd' since we removed it from 'now'
    delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
@@ -62,6 +59,9 @@ def timeuntil(d, now=None):
    Like timesince, but returns a string measuring the time until
    the given time.
    """
    if now == None:
    if not now:
        if d.tzinfo:
            now = datetime.datetime.now(LocalTimezone(d))
        else:
            now = datetime.datetime.now()
    return timesince(now, d)
+4 −0
Original line number Diff line number Diff line
@@ -1332,6 +1332,8 @@ For example, if ``blog_date`` is a date instance representing midnight on 1
June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006,
then ``{{ blog_date|timesince:comment_date }}`` would return "8 hours".

Comparing offset-naive and offset-aware datetimes will return an empty string.

Minutes is the smallest unit used, and "0 minutes" will be returned for any
date that is in the future relative to the comparison point.

@@ -1349,6 +1351,8 @@ Takes an optional argument that is a variable containing the date to use as
the comparison point (instead of *now*). If ``from_date`` contains 22 June
2006, then ``{{ conference_date|timeuntil:from_date }}`` will return "1 week".

Comparing offset-naive and offset-aware datetimes will return an empty string.

Minutes is the smallest unit used, and "0 minutes" will be returned for any
date that is in the past relative to the comparison point.

+13 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ consistent.

from datetime import datetime, timedelta

from django.utils.tzinfo import LocalTimezone
from django.utils.tzinfo import LocalTimezone, FixedOffset
from django.utils.safestring import mark_safe

# These two classes are used to test auto-escaping of __unicode__ output.
@@ -27,6 +27,7 @@ class SafeClass:
def get_filter_tests():
    now = datetime.now()
    now_tz = datetime.now(LocalTimezone(now))
    now_tz_i = datetime.now(FixedOffset((3 * 60) + 15)) # imaginary time zone
    return {
        # Default compare with datetime.now()
        'filter-timesince01' : ('{{ a|timesince }}', {'a': datetime.now() + timedelta(minutes=-1, seconds = -10)}, '1 minute'),
@@ -46,6 +47,14 @@ def get_filter_tests():
        'filter-timesince09': ('{{ later|timesince }}', { 'later': now + timedelta(days=7) }, '0 minutes'),
        'filter-timesince10': ('{{ later|timesince:now }}', { 'now': now, 'later': now + timedelta(days=7) }, '0 minutes'),

        # Ensures that differing timezones are calculated correctly
        'filter-timesince11' : ('{{ a|timesince }}', {'a': now}, '0 minutes'),
        'filter-timesince12' : ('{{ a|timesince }}', {'a': now_tz}, '0 minutes'),
        'filter-timesince13' : ('{{ a|timesince }}', {'a': now_tz_i}, '0 minutes'),
        'filter-timesince14' : ('{{ a|timesince:b }}', {'a': now_tz, 'b': now_tz_i}, '0 minutes'),
        'filter-timesince15' : ('{{ a|timesince:b }}', {'a': now, 'b': now_tz_i}, ''),
        'filter-timesince16' : ('{{ a|timesince:b }}', {'a': now_tz_i, 'b': now}, ''),

        # Default compare with datetime.now()
        'filter-timeuntil01' : ('{{ a|timeuntil }}', {'a':datetime.now() + timedelta(minutes=2, seconds = 10)}, '2 minutes'),
        'filter-timeuntil02' : ('{{ a|timeuntil }}', {'a':(datetime.now() + timedelta(days=1, seconds = 10))}, '1 day'),
@@ -61,6 +70,9 @@ def get_filter_tests():
        'filter-timeuntil08': ('{{ later|timeuntil }}', { 'later': now + timedelta(days=7, hours=1) }, '1 week'),
        'filter-timeuntil09': ('{{ later|timeuntil:now }}', { 'now': now, 'later': now + timedelta(days=7) }, '1 week'),

        # Ensures that differing timezones are calculated correctly
        'filter-timeuntil10' : ('{{ a|timeuntil }}', {'a': now_tz_i}, '0 minutes'),
        'filter-timeuntil11' : ('{{ a|timeuntil:b }}', {'a': now_tz_i, 'b': now_tz}, '0 minutes'),

        'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "<a>'", "b": mark_safe("<a>'")}, ur"<a>\' <a>\'"),
        'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, ur"&lt;a&gt;\&#39; <a>\'"),
Loading