Formatting timedelta objects

But I was wondering if I can do it in a single line using any date time function like strftime.

As far as I can tell, there isn't a built-in method to timedelta that does that. If you're doing it often, you can create your own function, e.g.

def strfdelta(tdelta, fmt):
    d = {"days": tdelta.days}
    d["hours"], rem = divmod(tdelta.seconds, 3600)
    d["minutes"], d["seconds"] = divmod(rem, 60)
    return fmt.format(**d)

Usage:

>>> print strfdelta(delta_obj, "{days} days {hours}:{minutes}:{seconds}")
1 days 20:18:12
>>> print strfdelta(delta_obj, "{hours} hours and {minutes} to go")
20 hours and 18 to go

If you want to use a string format closer to the one used by strftime we can employ string.Template:

from string import Template

class DeltaTemplate(Template):
    delimiter = "%"

def strfdelta(tdelta, fmt):
    d = {"D": tdelta.days}
    d["H"], rem = divmod(tdelta.seconds, 3600)
    d["M"], d["S"] = divmod(rem, 60)
    t = DeltaTemplate(fmt)
    return t.substitute(**d)

Usage:

>>> print strfdelta(delta_obj, "%D days %H:%M:%S")
1 days 20:18:12
>>> print strfdelta(delta_obj, "%H hours and %M to go")
20 hours and 18 to go

The totalSeconds value is shown as 13374 instead of 99774. I.e. it's ignoring the "day" value.

Note in the example above that you can use timedelta.days to get the "day" value.

Alternatively, from Python 2.7 onwards, timedelta has a total_seconds() method which return the total number of seconds contained in the duration.


A slight variant on Shawn Chin's answer - that also addresses a subsequent issue raised by mpouncett - pads the hours, minutes and seconds with leading zeros to ensure that all 3 elements use 2 places (more consistent with the specification for these fields in strftime):

from string import Template

class DeltaTemplate(Template):
    delimiter = "%"

def strfdelta(tdelta, fmt):
    d = {"D": tdelta.days}
    hours, rem = divmod(tdelta.seconds, 3600)
    minutes, seconds = divmod(rem, 60)
    d["H"] = '{:02d}'.format(hours)
    d["M"] = '{:02d}'.format(minutes)
    d["S"] = '{:02d}'.format(seconds)
    t = DeltaTemplate(fmt)
    return t.substitute(**d)

Here are is a test for some sample values:

from datetime import timedelta
for seconds in [0, 1, 59, 60, 61, 3599, 3600, 3601]:
    print strfdelta(timedelta(0, seconds), '%H:%M:%S')

And here is the output:

00:00:00
00:00:01
00:00:59
00:01:00
00:01:01
00:59:59
01:00:00
01:00:01