Ticket #22355: timedelta_templatetag_with_tests_and_docs.diff

File timedelta_templatetag_with_tests_and_docs.diff, 8.4 KB (added by Anoop Thomas Mathew, 10 years ago)

patch for delta filter for humanizing datetime.timedelta objects with tests and docs

  • django/template/defaultfilters.py

    diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
    index 76c0121..589bdd9 100644
    a b from django.utils.http import urlquote  
    1818from django.utils.text import Truncator, wrap, phone2numeric
    1919from django.utils.safestring import mark_safe, SafeData, mark_for_escaping
    2020from django.utils import six
    21 from django.utils.timesince import timesince, timeuntil
     21from django.utils.timesince import timesince, timeuntil, delta
    2222from django.utils.translation import ugettext, ungettext
    2323from django.utils.text import normalize_newlines
    2424
    def timeuntil_filter(value, arg=None):  
    743743    except (ValueError, TypeError):
    744744        return ''
    745745
     746@register.filter("delta", is_safe=False)
     747def delta_filter(value):
     748    """Humanizes a timedelta object on template (i.e. "2 months, 2 weeks")."""
     749    if not value:
     750        return ''
     751    try:
     752        return delta(value)
     753    except (ValueError, TypeError):
     754        return ''
     755
    746756###################
    747757# LOGIC           #
    748758###################
  • django/utils/timesince.py

    diff --git a/django/utils/timesince.py b/django/utils/timesince.py
    index 8fb0f64..0c57544 100644
    a b from django.utils.html import avoid_wrapping  
    66from django.utils.timezone import is_aware, utc
    77from django.utils.translation import ugettext, ungettext_lazy
    88
    9 def timesince(d, now=None, reversed=False):
     9def time_to_text(time_delta):
    1010    """
    11     Takes two datetime objects and returns the time between d and now
    12     as a nicely formatted string, e.g. "10 minutes".  If d occurs after now,
    13     then "0 minutes" is returned.
    14 
    15     Units used are years, months, weeks, days, hours, and minutes.
    16     Seconds and microseconds are ignored.  Up to two adjacent units will be
    17     displayed.  For example, "2 weeks, 3 days" and "1 year, 3 months" are
    18     possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
    19 
    20     Adapted from
    21     http://web.archive.org/web/20060617175230/http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
     11    Converts a datetime.timedelta object into a nicely formatted
     12    humanized string. Used by timesince, timeuntil and delta utils functions
    2213    """
    2314    chunks = (
    2415        (60 * 60 * 24 * 365, ungettext_lazy('%d year', '%d years')),
    def timesince(d, now=None, reversed=False):  
    2819        (60 * 60, ungettext_lazy('%d hour', '%d hours')),
    2920        (60, ungettext_lazy('%d minute', '%d minutes'))
    3021    )
    31     # Convert datetime.date to datetime.datetime for comparison.
    32     if not isinstance(d, datetime.datetime):
    33         d = datetime.datetime(d.year, d.month, d.day)
    34     if now and not isinstance(now, datetime.datetime):
    35         now = datetime.datetime(now.year, now.month, now.day)
    36 
    37     if not now:
    38         now = datetime.datetime.now(utc if is_aware(d) else None)
    39 
    40     delta = (d - now) if reversed else (now - d)
    4122    # ignore microseconds
    4223    since = delta.days * 24 * 60 * 60 + delta.seconds
    4324    if since <= 0:
    def timesince(d, now=None, reversed=False):  
    5637            result += ugettext(', ') + avoid_wrapping(name2 % count2)
    5738    return result
    5839
     40def timesince(d, now=None, reversed=False):
     41    """
     42    Takes two datetime objects and returns the time between d and now
     43    as a nicely formatted string, e.g. "10 minutes".  If d occurs after now,
     44    then "0 minutes" is returned.
     45
     46    Units used are years, months, weeks, days, hours, and minutes.
     47    Seconds and microseconds are ignored.  Up to two adjacent units will be
     48    displayed.  For example, "2 weeks, 3 days" and "1 year, 3 months" are
     49    possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
     50
     51    Adapted from
     52    http://web.archive.org/web/20060617175230/http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
     53    """
     54
     55    if isinstance(d, datetime.timedelta):
     56        time_delta = d
     57    else:
     58        # Convert datetime.date to datetime.datetime for comparison.
     59        if not isinstance(d, datetime.datetime):
     60            d = datetime.datetime(d.year, d.month, d.day)
     61        if now and not isinstance(now, datetime.datetime):
     62            now = datetime.datetime(now.year, now.month, now.day)
     63        if not now:
     64            now = datetime.datetime.now(utc if is_aware(d) else None)
     65        time_delta = (d - now) if reversed else (now - d)
     66    result = time_to_text(time_delta)
     67    return result
     68
    5969def timeuntil(d, now=None):
    6070    """
    6171    Like timesince, but returns a string measuring the time until
    6272    the given time.
    6373    """
    6474    return timesince(d, now, reversed=True)
     75
     76def delta(time_delta):
     77    """
     78    Returns seconds duration as weeks, days, hours, minutes, seconds
     79    Similar to timesince/timeuntil, but works with datetime.timedelta
     80    """
     81    return timesince(time_delta)
     82 No newline at end of file
  • docs/ref/templates/builtins.txt

    diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
    index 9d096e4..15ea5c6 100644
    a b Comparing offset-naive and offset-aware datetimes will return an empty string.  
    20882088Minutes is the smallest unit used, and "0 minutes" will be returned for any
    20892089date that is in the past relative to the comparison point.
    20902090
     2091.. templatefilter:: delta
     2092
     2093delta
     2094^^^^^^^^^
     2095
     2096Similar to ``timesince`` and ``timeuntil``, except that it can take timedelta
     2097as argument. For example, if user has been working on a task for a timespan,
     2098and``working_time`` is a timedelta instance holding
     2099``datetime.timedelta(1, 43199, 999989)``, then ``{{ working_time|delta }}``
     2100will return "1 day, 11 hours".
     2101
     2102
     2103As like ``timesince`` and ``timeuntil``, minutes is the smallest unit used,
     2104and "0 minutes" will be returned for any date that is in the past relative
     2105to the comparison point.
     2106
    20912107.. templatefilter:: title
    20922108
    20932109title
  • tests/defaultfilters/tests.py

    diff --git a/tests/defaultfilters/tests.py b/tests/defaultfilters/tests.py
    index 6f84c14..af1dab7 100644
    a b class DefaultFiltersTests(TestCase):  
    552552                             datetime.datetime(2005, 12, 29)),
    553553            '1\xa0day')
    554554
     555    def test_delta(self):
     556        self.assertEqual(
     557            delta_filter(datetime.timedelta(29, 64788)),
     558                         '4\xa0weeks, 1\xa0day')
     559
    555560    def test_default(self):
    556561        self.assertEqual(default("val", "default"), 'val')
    557562        self.assertEqual(default(None, "default"), 'default')
  • tests/template_tests/filters.py

    diff --git a/tests/template_tests/filters.py b/tests/template_tests/filters.py
    index 142f56f..73f98da 100644
    a b def get_filter_tests():  
    9090        'filter-timeuntil12' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today}, '0\xa0minutes'),
    9191        'filter-timeuntil13' : ('{{ a|timeuntil:b }}', {'a': today, 'b': today - timedelta(hours=24)}, '1\xa0day'),
    9292
     93        # Compare to a given parameter
     94        'filter-delta01' : ('{{ a|delta }}', {'a': timedelta(29, 64788)}, u'4\xa0weeks, 1\xa0day'),
     95        'filter-delta02' : ('{{ a|delta }}', {'a': now - (datetime.now() - timedelta(hours=36))}, '1\xa0day, 11\xa0hours'),
     96
    9397        'filter-addslash01': ("{% autoescape off %}{{ a|addslashes }} {{ b|addslashes }}{% endautoescape %}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"<a>\' <a>\'"),
    9498        'filter-addslash02': ("{{ a|addslashes }} {{ b|addslashes }}", {"a": "<a>'", "b": mark_safe("<a>'")}, r"&lt;a&gt;\&#39; <a>\'"),
    9599
  • tests/utils_tests/test_timesince.py

    diff --git a/tests/utils_tests/test_timesince.py b/tests/utils_tests/test_timesince.py
    index cdb95e6..2cadd1d 100644
    a b from __future__ import unicode_literals  
    33import datetime
    44import unittest
    55
    6 from django.utils.timesince import timesince, timeuntil
     6from django.utils.timesince import timesince, timeuntil, delta
    77from django.utils.tzinfo import LocalTimezone, FixedOffset
    88
    99class TimesinceTests(unittest.TestCase):
    class TimesinceTests(unittest.TestCase):  
    123123        self.assertEqual(timesince(future), '0\xa0minutes')
    124124        past = datetime.datetime(1980, 1, 1, tzinfo=naive())
    125125        self.assertEqual(timeuntil(past), '0\xa0minutes')
     126
     127    def test_delta_with_timedelta_objects(self):
     128        time_delta = datetime.timedelta(1, 43199, 999989)
     129        self.assertEqual(delta(time_delta), '1\xa0day, 11\xa0hours')
     130
Back to Top