Fixed #15921 -- Refined naturaltime filter added in r16071 to use timesince and timeuntil filters as fallbacks instead of date filter.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16233 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-05-17 10:16:12 +00:00
parent 9ad005ec1c
commit 578a31fea3
5 changed files with 177 additions and 85 deletions

View File

@ -4,7 +4,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Django\n" "Project-Id-Version: Django\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-05-07 21:53+0200\n" "POT-Creation-Date: 2011-05-16 17:30+0200\n"
"PO-Revision-Date: 2010-05-13 15:35+0200\n" "PO-Revision-Date: 2010-05-13 15:35+0200\n"
"Last-Translator: Django team\n" "Last-Translator: Django team\n"
"Language-Team: English <en@li.org>\n" "Language-Team: English <en@li.org>\n"
@ -12,133 +12,166 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: templatetags/humanize.py:21 #: templatetags/humanize.py:25
msgid "th" msgid "th"
msgstr "" msgstr ""
#: templatetags/humanize.py:21 #: templatetags/humanize.py:25
msgid "st" msgid "st"
msgstr "" msgstr ""
#: templatetags/humanize.py:21 #: templatetags/humanize.py:25
msgid "nd" msgid "nd"
msgstr "" msgstr ""
#: templatetags/humanize.py:21 #: templatetags/humanize.py:25
msgid "rd" msgid "rd"
msgstr "" msgstr ""
#: templatetags/humanize.py:74 #: templatetags/humanize.py:78
#, python-format #, python-format
msgid "%(value).1f million" msgid "%(value).1f million"
msgid_plural "%(value).1f million" msgid_plural "%(value).1f million"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:75 #: templatetags/humanize.py:79
#, python-format #, python-format
msgid "%(value)s million" msgid "%(value)s million"
msgid_plural "%(value)s million" msgid_plural "%(value)s million"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:80 #: templatetags/humanize.py:84
#, python-format #, python-format
msgid "%(value).1f billion" msgid "%(value).1f billion"
msgid_plural "%(value).1f billion" msgid_plural "%(value).1f billion"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:81 #: templatetags/humanize.py:85
#, python-format #, python-format
msgid "%(value)s billion" msgid "%(value)s billion"
msgid_plural "%(value)s billion" msgid_plural "%(value)s billion"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:86 #: templatetags/humanize.py:90
#, python-format #, python-format
msgid "%(value).1f trillion" msgid "%(value).1f trillion"
msgid_plural "%(value).1f trillion" msgid_plural "%(value).1f trillion"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:87 #: templatetags/humanize.py:91
#, python-format #, python-format
msgid "%(value)s trillion" msgid "%(value)s trillion"
msgid_plural "%(value)s trillion" msgid_plural "%(value)s trillion"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "one" msgid "one"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "two" msgid "two"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "three" msgid "three"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "four" msgid "four"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "five" msgid "five"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "six" msgid "six"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "seven" msgid "seven"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "eight" msgid "eight"
msgstr "" msgstr ""
#: templatetags/humanize.py:104 #: templatetags/humanize.py:108
msgid "nine" msgid "nine"
msgstr "" msgstr ""
#: templatetags/humanize.py:127 #: templatetags/humanize.py:131
msgid "today" msgid "today"
msgstr "" msgstr ""
#: templatetags/humanize.py:129 #: templatetags/humanize.py:133
msgid "tomorrow" msgid "tomorrow"
msgstr "" msgstr ""
#: templatetags/humanize.py:131 #: templatetags/humanize.py:135
msgid "yesterday" msgid "yesterday"
msgstr "" msgstr ""
#: templatetags/humanize.py:153 #: templatetags/humanize.py:160
#, python-format
msgctxt "naturaltime"
msgid "%(delta)s ago"
msgstr ""
#: templatetags/humanize.py:163 templatetags/humanize.py:185
msgid "now" msgid "now"
msgstr "" msgstr ""
#: templatetags/humanize.py:155 #: templatetags/humanize.py:166
#, python-format #, python-format
msgid "%s seconds ago" msgid "a second ago"
msgid_plural "%s seconds ago" msgid_plural "%(count)s seconds ago"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:157 #: templatetags/humanize.py:171
#, python-format #, python-format
msgid "a minute ago" msgid "a minute ago"
msgid_plural "%s minutes ago" msgid_plural "%(count)s minutes ago"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: templatetags/humanize.py:159 #: templatetags/humanize.py:176
#, python-format #, python-format
msgid "an hour ago" msgid "an hour ago"
msgid_plural "%s hours ago" msgid_plural "%(count)s hours ago"
msgstr[0] ""
msgstr[1] ""
#: templatetags/humanize.py:182
#, python-format
msgctxt "naturaltime"
msgid "%(delta)s from now"
msgstr ""
#: templatetags/humanize.py:188
#, python-format
msgid "a second from now"
msgid_plural "%(count)s seconds from now"
msgstr[0] ""
msgstr[1] ""
#: templatetags/humanize.py:193
#, python-format
msgid "a minute from now"
msgid_plural "%(count)s minutes from now"
msgstr[0] ""
msgstr[1] ""
#: templatetags/humanize.py:198
#, python-format
msgid "an hour from now"
msgid_plural "%(count)s hours from now"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""

View File

@ -1,11 +1,15 @@
from django.utils.translation import ungettext, ugettext as _ import re
from datetime import date, datetime, timedelta
from django import template
from django.conf import settings
from django.template import defaultfilters
from django.utils.datetime_safe import datetime, date
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from django.utils.formats import number_format from django.utils.formats import number_format
from django import template from django.utils.translation import pgettext, ungettext, ugettext as _
from django.template import defaultfilters from django.utils.tzinfo import LocalTimezone
from django.conf import settings
from datetime import date, datetime
import re
register = template.Library() register = template.Library()
@ -132,11 +136,10 @@ def naturalday(value, arg=None):
return defaultfilters.date(value, arg) return defaultfilters.date(value, arg)
@register.filter @register.filter
def naturaltime(value, arg=None): def naturaltime(value):
""" """
For date and time values shows how many seconds, minutes or hours ago compared to For date and time values shows how many seconds, minutes or hours ago
current timestamp returns representing string. Otherwise, returns a string compared to current timestamp returns representing string.
formatted according to settings.DATE_FORMAT
""" """
try: try:
value = datetime(value.year, value.month, value.day, value.hour, value.minute, value.second) value = datetime(value.year, value.month, value.day, value.hour, value.minute, value.second)
@ -145,16 +148,52 @@ def naturaltime(value, arg=None):
except ValueError: except ValueError:
return value return value
delta = datetime.now() - value if getattr(value, 'tzinfo', None):
now = datetime.now(LocalTimezone(value))
else:
now = datetime.now()
now = now - timedelta(0, 0, now.microsecond)
if value < now:
delta = now - value
if delta.days != 0: if delta.days != 0:
value = date(value.year, value.month, value.day) return pgettext(
return naturalday(value, arg) 'naturaltime', '%(delta)s ago'
) % {'delta': defaultfilters.timesince(value)}
elif delta.seconds == 0: elif delta.seconds == 0:
return _(u'now') return _(u'now')
elif delta.seconds < 60: elif delta.seconds < 60:
return ungettext(u'%s seconds ago', u'%s seconds ago', delta.seconds) return ungettext(
u'a second ago', u'%(count)s seconds ago', delta.seconds
) % {'count': delta.seconds}
elif delta.seconds / 60 < 60: elif delta.seconds / 60 < 60:
return ungettext(u'a minute ago', u'%s minutes ago', delta.seconds/60) count = delta.seconds / 60
elif delta.seconds / 60 / 60 < 24: return ungettext(
return ungettext(u'an hour ago', u'%s hours ago', delta.seconds/60/60) u'a minute ago', u'%(count)s minutes ago', count
return naturalday(value, arg) ) % {'count': count}
else:
count = delta.seconds / 60 / 60
return ungettext(
u'an hour ago', u'%(count)s hours ago', count
) % {'count': count}
else:
delta = value - now
if delta.days != 0:
return pgettext(
'naturaltime', '%(delta)s from now'
) % {'delta': defaultfilters.timeuntil(value)}
elif delta.seconds == 0:
return _(u'now')
elif delta.seconds < 60:
return ungettext(
u'a second from now', u'%(count)s seconds from now', delta.seconds
) % {'count': delta.seconds}
elif delta.seconds / 60 < 60:
count = delta.seconds / 60
return ungettext(
u'a minute from now', u'%(count)s minutes from now', count
) % {'count': count}
else:
count = delta.seconds / 60 / 60
return ungettext(
u'an hour from now', u'%(count)s hours from now', count
) % {'count': count}

View File

@ -104,9 +104,8 @@ naturaltime
For datetime values, returns a string representing how many seconds, For datetime values, returns a string representing how many seconds,
minutes or hours ago it was -- falling back to a longer date format if the minutes or hours ago it was -- falling back to a longer date format if the
value is more than a day old. value is more than a day old. In case the datetime value is in the future
the return value will automatically use an appropriate phrase.
**Argument:** Date formatting string as described in the :tfilter:`date` tag.
Examples (when 'now' is 17 Feb 2007 16:30:00): Examples (when 'now' is 17 Feb 2007 16:30:00):
@ -116,9 +115,13 @@ Examples (when 'now' is 17 Feb 2007 16:30:00):
* ``17 Feb 2007 16:25:35`` becomes ``4 minutes ago``. * ``17 Feb 2007 16:25:35`` becomes ``4 minutes ago``.
* ``17 Feb 2007 15:30:29`` becomes ``an hour ago``. * ``17 Feb 2007 15:30:29`` becomes ``an hour ago``.
* ``17 Feb 2007 13:31:29`` becomes ``2 hours ago``. * ``17 Feb 2007 13:31:29`` becomes ``2 hours ago``.
* ``16 Feb 2007 13:31:29`` becomes ``yesterday``. * ``16 Feb 2007 13:31:29`` becomes ``1 day ago``.
* Any other day is formatted according to given argument or the * ``17 Feb 2007 16:30:30`` becomes ``29 seconds from now``.
:setting:`DATE_FORMAT` setting if no argument is given. * ``17 Feb 2007 16:31:00`` becomes ``a minute from now``.
* ``17 Feb 2007 16:34:35`` becomes ``4 minutes from now``.
* ``17 Feb 2007 16:30:29`` becomes ``an hour from now``.
* ``17 Feb 2007 18:31:29`` becomes ``2 hours from now``.
* ``18 Feb 2007 16:31:29`` becomes ``1 day from now``.
.. templatefilter:: ordinal .. templatefilter:: ordinal

View File

@ -89,31 +89,6 @@ class HumanizeTests(TestCase):
someday_result, u"I'm not a date value", None) someday_result, u"I'm not a date value", None)
self.humanize_tester(test_list, result_list, 'naturalday') self.humanize_tester(test_list, result_list, 'naturalday')
def test_naturaltime(self):
from django.template import defaultfilters
now = datetime.now()
seconds_ago = now - timedelta(seconds=30)
a_minute_ago = now - timedelta(minutes=1, seconds=30)
minutes_ago = now - timedelta(minutes=2)
an_hour_ago = now - timedelta(hours=1, minutes=30, seconds=30)
hours_ago = now - timedelta(hours=23, minutes=50, seconds=50)
test_list = (now, a_minute_ago, an_hour_ago)
result_list = (_(u'now'), _(u'a minute ago'), _(u'an hour ago'))
self.humanize_tester(test_list, result_list, 'naturaltime')
t = Template('{{ seconds_ago|%s }}' % 'naturaltime')
rendered = t.render(Context(locals())).strip()
self.assertTrue(u' seconds ago' in rendered)
t = Template('{{ minutes_ago|%s }}' % 'naturaltime')
rendered = t.render(Context(locals())).strip()
self.assertTrue(u' minutes ago' in rendered)
t = Template('{{ hours_ago|%s }}' % 'naturaltime')
rendered = t.render(Context(locals())).strip()
self.assertTrue(u' hours ago' in rendered)
def test_naturalday_tz(self): def test_naturalday_tz(self):
from django.contrib.humanize.templatetags.humanize import naturalday from django.contrib.humanize.templatetags.humanize import naturalday
@ -130,3 +105,45 @@ class HumanizeTests(TestCase):
# As 24h of difference they will never be the same # As 24h of difference they will never be the same
self.assertNotEqual(naturalday_one, naturalday_two) self.assertNotEqual(naturalday_one, naturalday_two)
def test_naturaltime(self):
now = datetime.now()
test_list = [
now,
now - timedelta(seconds=1),
now - timedelta(seconds=30),
now - timedelta(minutes=1, seconds=30),
now - timedelta(minutes=2),
now - timedelta(hours=1, minutes=30, seconds=30),
now - timedelta(hours=23, minutes=50, seconds=50),
now - timedelta(days=1),
now - timedelta(days=500),
now + timedelta(seconds=1),
now + timedelta(seconds=30),
now + timedelta(minutes=1, seconds=30),
now + timedelta(minutes=2),
now + timedelta(hours=1, minutes=30, seconds=30),
now + timedelta(hours=23, minutes=50, seconds=50),
now + timedelta(days=1),
now + timedelta(days=500),
]
result_list = [
'now',
'a second ago',
'30 seconds ago',
'a minute ago',
'2 minutes ago',
'an hour ago',
'23 hours ago',
'1 day ago',
'1 year, 4 months ago',
'a second from now',
'30 seconds from now',
'a minute from now',
'2 minutes from now',
'an hour from now',
'23 hours from now',
'1 day from now',
'1 year, 4 months from now',
]
self.humanize_tester(test_list, result_list, 'naturaltime')