Fixed #12771 -- Added naturaltime filter to humanize contrib app. Thanks, phinpho, djansoft and xtrqt.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16071 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-04-22 12:02:47 +00:00
parent 8b588747ed
commit ea248f0107
3 changed files with 86 additions and 3 deletions

View File

@ -2,7 +2,7 @@ from django.utils.translation import ungettext, ugettext as _
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from django import template from django import template
from django.template import defaultfilters from django.template import defaultfilters
from datetime import date from datetime import date, datetime
import re import re
register = template.Library() register = template.Library()
@ -83,7 +83,7 @@ def naturalday(value, arg=None):
present day returns representing string. Otherwise, returns a string present day returns representing string. Otherwise, returns a string
formatted according to settings.DATE_FORMAT. formatted according to settings.DATE_FORMAT.
""" """
try: try:
value = date(value.year, value.month, value.day) value = date(value.year, value.month, value.day)
except AttributeError: except AttributeError:
# Passed value wasn't a date object # Passed value wasn't a date object
@ -100,3 +100,35 @@ def naturalday(value, arg=None):
return _(u'yesterday') return _(u'yesterday')
return defaultfilters.date(value, arg) return defaultfilters.date(value, arg)
register.filter(naturalday) register.filter(naturalday)
def naturaltime(value, arg=None):
"""
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
"""
try:
value = datetime(value.year, value.month, value.day, value.hour, value.minute, value.second)
except AttributeError:
return value
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 _(u'%s seconds ago' % (delta.seconds))
elif delta.seconds / 60 < 2:
return _(r'a minute ago')
elif delta.seconds / 60 < 60:
return _(u'%s minutes ago' % (delta.seconds/60))
elif delta.seconds / 60 / 60 < 2:
return _(u'an hour ago')
elif delta.seconds / 60 / 60 < 24:
return _(u'%s hours ago' % (delta.seconds/60/60))
return naturalday(value, arg)
register.filter(naturaltime)

View File

@ -82,6 +82,31 @@ Examples (when 'today' is 17 Feb 2007):
* Any other day is formatted according to given argument or the * Any other day is formatted according to given argument or the
:setting:`DATE_FORMAT` setting if no argument is given. :setting:`DATE_FORMAT` setting if no argument is given.
.. templatefilter:: naturaltime
naturaltime
-----------
.. versionadded:: 1.4
For date and time values shows how many seconds, minutes or hours ago compared
to current timestamp returns representing string. Otherwise, it behaves like
:tfilter:`naturaldate`, so it can also take string argument for date formating.
**Argument:** Date formatting string as described in the :tfilter:`date` tag.
Examples (when 'now' is 17 Feb 2007 16:30:00):
* ``17 Feb 2007 16:30:00`` becomes ``now``.
* ``17 Feb 2007 16:29:31`` becomes ``29 seconds ago``.
* ``17 Feb 2007 16:29:00`` becomes ``a minute ago``.
* ``17 Feb 2007 16:25:35`` becomes ``4 minutes ago``.
* ``17 Feb 2007 15:30:29`` becomes ``an hours 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.
.. templatefilter:: ordinal .. templatefilter:: ordinal
ordinal ordinal

View File

@ -1,4 +1,4 @@
from datetime import timedelta, date from datetime import timedelta, date, datetime
from django.template import Template, Context, add_to_builtins from django.template import Template, Context, add_to_builtins
from django.utils import unittest from django.utils import unittest
@ -72,6 +72,32 @@ class HumanizeTests(unittest.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)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()