[Django]-Convert seconds to hh:mm:ss in Python

222đź‘Ť

âś…

I can’t believe any of the many answers gives what I’d consider the “one obvious way to do it” (and I’m not even Dutch…!-) — up to just below 24 hours’ worth of seconds (86399 seconds, specifically):

>>> import time
>>> time.strftime('%H:%M:%S', time.gmtime(12345))
'03:25:45'

Doing it in a Django template’s more finicky, since the time filter supports a funky time-formatting syntax (inspired, I believe, from PHP), and also needs the datetime module, and a timezone implementation such as pytz, to prep the data. For example:

>>> from django import template as tt
>>> import pytz
>>> import datetime
>>> tt.Template('{{ x|time:"H:i:s" }}').render(
...     tt.Context({'x': datetime.datetime.fromtimestamp(12345, pytz.utc)}))
u'03:25:45'

Depending on your exact needs, it might be more convenient to define a custom filter for this formatting task in your app.

👤Alex Martelli

114đź‘Ť

>>> a = datetime.timedelta(seconds=65)
datetime.timedelta(0, 65)
>>> str(a)
'0:01:05'
👤SilentGhost

29đź‘Ť

Read up on the datetime module.

SilentGhost’s answer has the details my answer leaves out and is reposted here:

>>> a = datetime.timedelta(seconds=65)
datetime.timedelta(0, 65)
>>> str(a)
'0:01:05'
👤Matt Howell

27đź‘Ť

Code that does what was requested, with examples, and showing how cases he didn’t specify are handled:

def format_seconds_to_hhmmss(seconds):
    hours = seconds // (60*60)
    seconds %= (60*60)
    minutes = seconds // 60
    seconds %= 60
    return "%02i:%02i:%02i" % (hours, minutes, seconds)

def format_seconds_to_mmss(seconds):
    minutes = seconds // 60
    seconds %= 60
    return "%02i:%02i" % (minutes, seconds)

minutes = 60
hours = 60*60
assert format_seconds_to_mmss(7*minutes + 30) == "07:30"
assert format_seconds_to_mmss(15*minutes + 30) == "15:30"
assert format_seconds_to_mmss(1000*minutes + 30) == "1000:30"

assert format_seconds_to_hhmmss(2*hours + 15*minutes + 30) == "02:15:30"
assert format_seconds_to_hhmmss(11*hours + 15*minutes + 30) == "11:15:30"
assert format_seconds_to_hhmmss(99*hours + 15*minutes + 30) == "99:15:30"
assert format_seconds_to_hhmmss(500*hours + 15*minutes + 30) == "500:15:30"

You can–and probably should–store this as a timedelta rather than an int, but that’s a separate issue and timedelta doesn’t actually make this particular task any easier.

👤Glenn Maynard

16đź‘Ť

You can calculate the number of minutes and hours from the number of seconds by simple division:

seconds = 12345
minutes = seconds // 60
hours = minutes // 60

print "%02d:%02d:%02d" % (hours, minutes % 60, seconds % 60)
print "%02d:%02d" % (minutes, seconds % 60)

Here // is Python’s integer division.

👤sth

12đź‘Ť

If you use divmod, you are immune to different flavors of integer division:

# show time strings for 3800 seconds

# easy way to get mm:ss
print "%02d:%02d" % divmod(3800, 60)

# easy way to get hh:mm:ss
from functools import reduce
print "%02d:%02d:%02d" % \
    reduce(lambda ll,b : divmod(ll[0],b) + ll[1:],
        [(3800,),60,60])


# function to convert floating point number of seconds to
# hh:mm:ss.sss
def secondsToStr(t):
    return "%02d:%02d:%02d.%03d" % \
        reduce(lambda ll,b : divmod(ll[0],b) + ll[1:],
            [(round(t*1000),),1000,60,60])

print secondsToStr(3800.123)

Prints:

63:20
01:03:20
01:03:20.123
👤PaulMcG

1đź‘Ť

Not being a Python person, but the easiest without any libraries is just:

total   = 3800
seconds = total % 60
total   = total - seconds
hours   = total / 3600
total   = total - (hours * 3600)
mins    = total / 60
👤gaqzi

1đź‘Ť

Just be careful when dividing by 60: division between integers returns an integer ->
12/60 = 0 unless you import division from future.
The following is copy and pasted from Python 2.6.2:

IDLE 2.6.2      
>>> 12/60
0
>>> from __future__ import division
>>> 12/60
0.20000000000000001
👤Francesco

0đź‘Ť

If you need to do this a lot, you can precalculate all possible strings for number of seconds in a day:

try:
    from itertools import product
except ImportError:
    def product(*seqs):
        if len(seqs) == 1:
            for p in seqs[0]:
                yield p,
        else:
            for s in seqs[0]:
                for p in product(*seqs[1:]):
                    yield (s,) + p

hhmmss = []
for (h, m, s) in product(range(24), range(60), range(60)):
    hhmmss.append("%02d:%02d:%02d" % (h, m, s))

Now conversion of seconds to format string is a fast indexed lookup:

print hhmmss[12345]

prints

'03:25:45'

EDIT:

Updated to 2020, removing Py2 compatibility ugliness, and f-strings!

import sys
from itertools import product


hhmmss = [f"{h:02d}:{m:02d}:{s:02d}"
             for h, m, s in product(range(24), range(60), range(60))]

# we can still just index into the list, but define as a function
# for common API with code below
seconds_to_str = hhmmss.__getitem__

print(seconds_to_str(12345))

How much memory does this take? sys.getsizeof of a list won’t do, since it will just give us the size of the list and its str refs, but not include the memory of the strs themselves:

# how big is a list of 24*60*60 8-character strs?
list_size = sys.getsizeof(hhmmss) + sum(sys.getsizeof(s) for s in hhmmss)
print("{:,}".format(list_size))

prints:

5,657,616

What if we just had one big str? Every value is exactly 8 characters long, so we can slice into this str and get the correct str for second X of the day:

hhmmss_str = ''.join([f"{h:02d}:{m:02d}:{s:02d}"
                      for h, m, s in product(range(24),
                                             range(60),
                                             range(60))])
def seconds_to_str(n):
    loc = n * 8
    return hhmmss_str[loc: loc+8]

print(seconds_to_str(12345))

Did that save any space?

# how big is a str of 24*60*60*8 characters?
str_size = sys.getsizeof(hhmmss_str)
print("{:,}".format(str_size))

prints:

691,249

Reduced to about this much:

print(str_size / list_size)

prints:

0.12218026108523448

On the performance side, this looks like a classic memory vs. CPU tradeoff:

import timeit

print("\nindex into pre-calculated list")
print(timeit.timeit("hhmmss[6]", '''from itertools import product; hhmmss = [f"{h:02d}:{m:02d}:{s:02d}"
                     for h, m, s in product(range(24),
                                             range(60),
                                             range(60))]'''))
print("\nget slice from pre-calculated str")
print(timeit.timeit("hhmmss_str[6*8:7*8]", '''from itertools import product; hhmmss_str=''.join([f"{h:02d}:{m:02d}:{s:02d}"
                     for h, m, s in product(range(24),
                                             range(60),
                                             range(60))])'''))

print("\nuse datetime.timedelta from stdlib")
print(timeit.timeit("timedelta(seconds=6)", "from datetime import timedelta"))
print("\ninline compute of h, m, s using divmod")
print(timeit.timeit("n=6;m,s=divmod(n,60);h,m=divmod(m,60);f'{h:02d}:{m:02d}:{s:02d}'"))

On my machine I get:

index into pre-calculated list
0.0434853

get slice from pre-calculated str
0.1085147

use datetime.timedelta from stdlib
0.7625738

inline compute of h, m, s using divmod
2.0477764
👤PaulMcG

-2đź‘Ť

Besides the fact that Python has built in support for dates and times (see bigmattyh’s response), finding minutes or hours from seconds is easy:

minutes = seconds / 60
hours = minutes / 60

Now, when you want to display minutes or seconds, MOD them by 60 so that they will not be larger than 59

👤Ed S.

Leave a comment