23

I'm having trouble getting my django template to display a timedelta object consistently. I tried using the time filter in my template, but nothing is displayed when I do this. The timedelta object is shown as follows on the errors page if I use Assert False:

time    datetime.timedelta(0, 38, 132827)

This displays the time difference as:

0:00:38.132827

I would like to only show the hours, minutes, and seconds for each timedelta object. Does anyone have any suggestions on how I can do this?

bgmaster
  • 2,313
  • 4
  • 28
  • 41
  • 1
    This similar question for Django might be helpful: https://stackoverflow.com/questions/33105457/display-and-format-django-durationfield-in-template – Anupam Jan 07 '20 at 14:25
  • Does this answer your question? [Display and format Django DurationField in template](https://stackoverflow.com/questions/33105457/display-and-format-django-durationfield-in-template) – kloddant Dec 14 '20 at 18:28
  • Although it asks for a different output format (and came first), this question is essentially the same as https://stackoverflow.com/questions/33105457/display-and-format-django-durationfield-in-template/65293775. I know this post is old and already has an answer, but I have answered it there in a more robust format, mostly for others and so that when I inevitably google this again and get this page as a result, I can see the answer that I want. – kloddant Dec 14 '20 at 18:32
  • I'm not sure since when, but for anyone searching for this, Django has a built-in filter "timesince" (and timeuntil) which display the timedelta in a nice human readable format (e.g., “4 days, 6 hours”). See the docs here: https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#timesince – SuzukiBKing Mar 24 '21 at 06:30

6 Answers6

10

I followed Peter's advice and wrote a custom template filter.

Here's the steps I took.

First I followed this guide to create a custom template filter.

Be sure to read this section on code layout.

Here's my filter code

from django import template

register = template.Library()

@register.filter()
def smooth_timedelta(timedeltaobj):
    """Convert a datetime.timedelta object into Days, Hours, Minutes, Seconds."""
    secs = timedeltaobj.total_seconds()
    timetot = ""
    if secs > 86400: # 60sec * 60min * 24hrs
        days = secs // 86400
        timetot += "{} days".format(int(days))
        secs = secs - days*86400

    if secs > 3600:
        hrs = secs // 3600
        timetot += " {} hours".format(int(hrs))
        secs = secs - hrs*3600

    if secs > 60:
        mins = secs // 60
        timetot += " {} minutes".format(int(mins))
        secs = secs - mins*60

    if secs > 0:
        timetot += " {} seconds".format(int(secs))
    return timetot

Then in my template I did

{% load smooth_timedelta %}

{% timedeltaobject|smooth_timedelta %}

Example output

enter image description here

chidimo
  • 2,684
  • 3
  • 32
  • 47
3

You can try remove the microseconds from the timedelta object, before sending it to the template:

time = time - datetime.timedelta(microseconds=time.microseconds)
lonemc
  • 48
  • 4
2

I don't think there's anything built in, and timedeltas don't directly expose their hour and minute values. but this package includes a timedelta custom filter tag that might help: http://pydoc.net/django-timedeltafield/0.7.10/

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
1

The advice to write your own custom template tag is 100% the right way to go. You'll have complete control and can format it anyway you like. BUT -- if you're lazy and want a quick solution using builtin django facilities, you can use a hackey technique using the built-in timesince tag.

Basically, subtract your timedelta from the current time and drop it into your template. For example

import datetime
import django.template

tdelta = datetime.timedelta(hours=5, minutes=10)
tm = datetime.datetime.utcnow() - tdelta

django_engine = django.template.engines['django']
template = django_engine.from_string("My delta {{ tm|timesince }}")
print(template.render({'tm': tm})

Execute the above code in ./manage.py shell and the output is:

My delta 5 hours, 10 minutes
user590028
  • 11,364
  • 3
  • 40
  • 57
0

As far as I know you have to write you're own template tag for this. Below is the one I've concocted based on the Django core timesince/timeuntil code that should output what you're after:

@register.simple_tag
def duration( duration ):
"""
Usage: {% duration timedelta %}
Returns seconds duration as weeks, days, hours, minutes, seconds
Based on core timesince/timeuntil
"""

    def seconds_in_units(seconds):
    """
    Returns a tuple containing the most appropriate unit for the
    number of seconds supplied and the value in that units form.

    >>> seconds_in_units(7700)
    (2, 'hour')
    """

        unit_totals = OrderedDict()

        unit_limits = [
                       ("week", 7 * 24 * 3600),
                       ("day", 24 * 3600),
                       ("hour", 3600),
                       ("minute", 60),
                       ("second", 1)
                        ]

        for unit_name, limit in unit_limits:
            if seconds >= limit:
                amount = int(float(seconds) / limit)
                if amount != 1:
                    unit_name += 's' # dodgy pluralisation
                unit_totals[unit_name] = amount
                seconds = seconds - ( amount * limit )

        return unit_totals;


if duration:
    if isinstance( duration, datetime.timedelta ):
        if duration.total_seconds > 0:
            unit_totals = seconds_in_units( duration.total_seconds() )
            return ', '.join([str(v)+" "+str(k) for (k,v) in unit_totals.iteritems()])

return 'None'
mfitzp
  • 15,275
  • 7
  • 50
  • 70
0
from datetime import datetime

start = datetime.now()

taken = datetime.now() - start

str(taken)

'0:03:08.243773'

str(taken).split('.')[0]

'0:03:08'
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
wyleu
  • 59
  • 4
  • 3
    Code only answers are not very useful on their own. It would help if you could add some detail explaining how/why it answers the question. – SiHa Sep 29 '16 at 11:53