Index: django/utils/timesince.py
===================================================================
--- django/utils/timesince.py (revision 8419)
+++ django/utils/timesince.py (working copy)
@@ -27,17 +27,14 @@
)
# 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 d.tzinfo:
- tz = LocalTimezone(d)
- else:
- tz = None
- now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)
+ d = datetime.datetime(d.year, d.month, d.day)
+ if not now:
+ if d.tzinfo:
+ now = datetime.datetime.now(LocalTimezone(d))
+ else:
+ now = datetime.datetime.now()
+
# ignore microsecond part of 'd' since we removed it from 'now'
delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
since = delta.days * 24 * 60 * 60 + delta.seconds
@@ -62,6 +59,9 @@
Like timesince, but returns a string measuring the time until
the given time.
"""
- if now == None:
- now = datetime.datetime.now()
+ if not now:
+ if d.tzinfo:
+ now = datetime.datetime.now(LocalTimezone(d))
+ else:
+ now = datetime.datetime.now()
return timesince(now, d)
Index: django/template/defaultfilters.py
===================================================================
--- django/template/defaultfilters.py (revision 8419)
+++ django/template/defaultfilters.py (working copy)
@@ -642,20 +642,24 @@
from django.utils.timesince import timesince
if not value:
return u''
- if arg:
- return timesince(arg, value)
- return timesince(value)
+ try:
+ if arg:
+ return timesince(arg, value)
+ 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
###################
Index: tests/regressiontests/templates/filters.py
===================================================================
--- tests/regressiontests/templates/filters.py (revision 8419)
+++ tests/regressiontests/templates/filters.py (working copy)
@@ -9,7 +9,7 @@
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.
@@ -20,13 +20,14 @@
class SafeClass:
def __unicode__(self):
return mark_safe(u'you > me')
-
+
# RESULT SYNTAX --
# 'template_name': ('template contents', 'context dict',
# 'expected string output' or Exception class)
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'),
@@ -40,6 +41,14 @@
# Check that timezone is respected
'filter-timesince06' : ('{{ a|timesince:b }}', {'a':now_tz + timedelta(hours=8), 'b':now_tz}, '8 hours'),
+ # Ensures that differing timezones are calculated correctly
+ 'filter-timesince07' : ('{{ a|timesince }}', {'a': now}, '0 minutes'),
+ 'filter-timesince08' : ('{{ a|timesince }}', {'a': now_tz}, '0 minutes'),
+ 'filter-timesince09' : ('{{ a|timesince }}', {'a': now_tz_i}, '0 minutes'),
+ 'filter-timesince10' : ('{{ a|timesince:b }}', {'a': now_tz, 'b': now_tz_i}, '0 minutes'),
+ 'filter-timesince11' : ('{{ a|timesince:b }}', {'a': now, 'b': now_tz_i}, ''),
+ 'filter-timesince12' : ('{{ 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'),
@@ -49,6 +58,10 @@
'filter-timeuntil04' : ('{{ a|timeuntil:b }}', {'a':now - timedelta(days=1), 'b':now - timedelta(days=2)}, '1 day'),
'filter-timeuntil05' : ('{{ a|timeuntil:b }}', {'a':now - timedelta(days=2), 'b':now - timedelta(days=2, minutes=1)}, '1 minute'),
+ # Ensures that differing timezones are calculated correctly
+ 'filter-timeuntil06' : ('{{ a|timeuntil }}', {'a': now_tz_i}, '0 minutes'),
+ 'filter-timeuntil07' : ('{{ a|timeuntil:b }}', {'a': now_tz_i, 'b': now_tz}, '0 minutes'),
+
'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "'", "b": mark_safe("'")}, ur"\' \'"),
'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "'", "b": mark_safe("'")}, ur"<a>\' \'"),
Index: tests/regressiontests/utils/timesince.py
===================================================================
--- tests/regressiontests/utils/timesince.py (revision 8419)
+++ tests/regressiontests/utils/timesince.py (working copy)
@@ -1,6 +1,7 @@
"""
>>> from datetime import datetime, timedelta
->>> from django.utils.timesince import timesince
+>>> from django.utils.timesince import timesince, timeuntil
+>>> from django.utils.tzinfo import LocalTimezone, FixedOffset
>>> t = datetime(2007, 8, 14, 13, 46, 0)
@@ -74,4 +75,13 @@
u'0 minutes'
>>> timesince(t, t-4*oneday-5*oneminute)
u'0 minutes'
+
+# When using two different timezones.
+>>> now = datetime.now()
+>>> now_tz = datetime.now(LocalTimezone(now))
+>>> now_tz_i = datetime.now(FixedOffset((3 * 60) + 15))
+>>> timesince(now_tz, now_tz_i)
+u'0 minutes'
+>>> timeuntil(now_tz, now_tz_i)
+u'0 minutes'
"""
Index: AUTHORS
===================================================================
--- AUTHORS (revision 8419)
+++ AUTHORS (working copy)
@@ -87,6 +87,7 @@
Juan Manuel Caicedo
Trevor Caira
Ricardo Javier Cárdenes Medina
+ Jeremy Carbaugh
Graham Carlyle
Antonio Cavedoni
C8E
Index: docs/templates.txt
===================================================================
--- docs/templates.txt (revision 8419)
+++ docs/templates.txt (working copy)
@@ -1763,6 +1763,8 @@
June 2006, and ``comment_date`` is a date instance for 08:00 on 1 June 2006,
then ``{{ comment_date|timesince:blog_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.
@@ -1778,6 +1780,8 @@
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.