diff --git a/django/contrib/humanize/locale/en/LC_MESSAGES/django.mo b/django/contrib/humanize/locale/en/LC_MESSAGES/django.mo index a08dc329d0..ba05bc9d70 100644 Binary files a/django/contrib/humanize/locale/en/LC_MESSAGES/django.mo and b/django/contrib/humanize/locale/en/LC_MESSAGES/django.mo differ diff --git a/django/contrib/humanize/locale/en/LC_MESSAGES/django.po b/django/contrib/humanize/locale/en/LC_MESSAGES/django.po index 0e7f3f33ed..360bdd94e6 100644 --- a/django/contrib/humanize/locale/en/LC_MESSAGES/django.po +++ b/django/contrib/humanize/locale/en/LC_MESSAGES/django.po @@ -4,7 +4,7 @@ msgid "" msgstr "" "Project-Id-Version: Django\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" "Last-Translator: Django team\n" "Language-Team: English \n" @@ -12,133 +12,166 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: templatetags/humanize.py:21 +#: templatetags/humanize.py:25 msgid "th" msgstr "" -#: templatetags/humanize.py:21 +#: templatetags/humanize.py:25 msgid "st" msgstr "" -#: templatetags/humanize.py:21 +#: templatetags/humanize.py:25 msgid "nd" msgstr "" -#: templatetags/humanize.py:21 +#: templatetags/humanize.py:25 msgid "rd" msgstr "" -#: templatetags/humanize.py:74 +#: templatetags/humanize.py:78 #, python-format msgid "%(value).1f million" msgid_plural "%(value).1f million" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:75 +#: templatetags/humanize.py:79 #, python-format msgid "%(value)s million" msgid_plural "%(value)s million" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:80 +#: templatetags/humanize.py:84 #, python-format msgid "%(value).1f billion" msgid_plural "%(value).1f billion" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:81 +#: templatetags/humanize.py:85 #, python-format msgid "%(value)s billion" msgid_plural "%(value)s billion" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:86 +#: templatetags/humanize.py:90 #, python-format msgid "%(value).1f trillion" msgid_plural "%(value).1f trillion" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:87 +#: templatetags/humanize.py:91 #, python-format msgid "%(value)s trillion" msgid_plural "%(value)s trillion" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "one" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "two" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "three" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "four" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "five" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "six" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "seven" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "eight" msgstr "" -#: templatetags/humanize.py:104 +#: templatetags/humanize.py:108 msgid "nine" msgstr "" -#: templatetags/humanize.py:127 +#: templatetags/humanize.py:131 msgid "today" msgstr "" -#: templatetags/humanize.py:129 +#: templatetags/humanize.py:133 msgid "tomorrow" msgstr "" -#: templatetags/humanize.py:131 +#: templatetags/humanize.py:135 msgid "yesterday" 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" msgstr "" -#: templatetags/humanize.py:155 +#: templatetags/humanize.py:166 #, python-format -msgid "%s seconds ago" -msgid_plural "%s seconds ago" +msgid "a second ago" +msgid_plural "%(count)s seconds ago" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:157 +#: templatetags/humanize.py:171 #, python-format msgid "a minute ago" -msgid_plural "%s minutes ago" +msgid_plural "%(count)s minutes ago" msgstr[0] "" msgstr[1] "" -#: templatetags/humanize.py:159 +#: templatetags/humanize.py:176 #, python-format 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[1] "" diff --git a/django/contrib/humanize/templatetags/humanize.py b/django/contrib/humanize/templatetags/humanize.py index 560f2a49ec..7a4defd392 100644 --- a/django/contrib/humanize/templatetags/humanize.py +++ b/django/contrib/humanize/templatetags/humanize.py @@ -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.formats import number_format -from django import template -from django.template import defaultfilters -from django.conf import settings -from datetime import date, datetime -import re +from django.utils.translation import pgettext, ungettext, ugettext as _ +from django.utils.tzinfo import LocalTimezone + register = template.Library() @@ -132,11 +136,10 @@ def naturalday(value, arg=None): return defaultfilters.date(value, arg) @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 - current timestamp returns representing string. Otherwise, returns a string - formatted according to settings.DATE_FORMAT + For date and time values shows how many seconds, minutes or hours ago + compared to current timestamp returns representing string. """ try: 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: return value - delta = datetime.now() - value - if delta.days != 0: - value = date(value.year, value.month, value.day) - return naturalday(value, arg) - elif delta.seconds == 0: - return _(u'now') - elif delta.seconds < 60: - return ungettext(u'%s seconds ago', u'%s seconds ago', delta.seconds) - elif delta.seconds / 60 < 60: - return ungettext(u'a minute ago', u'%s minutes ago', delta.seconds/60) - elif delta.seconds / 60 / 60 < 24: - return ungettext(u'an hour ago', u'%s hours ago', delta.seconds/60/60) - return naturalday(value, arg) + 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: + return pgettext( + 'naturaltime', '%(delta)s ago' + ) % {'delta': defaultfilters.timesince(value)} + elif delta.seconds == 0: + return _(u'now') + elif delta.seconds < 60: + return ungettext( + u'a second ago', u'%(count)s seconds ago', delta.seconds + ) % {'count': delta.seconds} + elif delta.seconds / 60 < 60: + count = delta.seconds / 60 + return ungettext( + u'a minute ago', u'%(count)s minutes ago', count + ) % {'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} diff --git a/docs/ref/contrib/humanize.txt b/docs/ref/contrib/humanize.txt index 5cacf2b97d..2f544c7ef7 100644 --- a/docs/ref/contrib/humanize.txt +++ b/docs/ref/contrib/humanize.txt @@ -104,9 +104,8 @@ naturaltime 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 -value is more than a day old. - -**Argument:** Date formatting string as described in the :tfilter:`date` tag. +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. 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 15:30:29`` becomes ``an hour ago``. * ``17 Feb 2007 13:31:29`` becomes ``2 hours ago``. - * ``16 Feb 2007 13:31:29`` becomes ``yesterday``. - * Any other day is formatted according to given argument or the - :setting:`DATE_FORMAT` setting if no argument is given. + * ``16 Feb 2007 13:31:29`` becomes ``1 day ago``. + * ``17 Feb 2007 16:30:30`` becomes ``29 seconds from now``. + * ``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 diff --git a/tests/regressiontests/humanize/tests.py b/tests/regressiontests/humanize/tests.py index bc1bf26636..370575a84a 100644 --- a/tests/regressiontests/humanize/tests.py +++ b/tests/regressiontests/humanize/tests.py @@ -89,31 +89,6 @@ class HumanizeTests(TestCase): someday_result, u"I'm not a date value", None) 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): 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 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')