How do I convert seconds to hours, minutes and seconds? - python

I have a function that returns information in seconds, but I need to store that information in hours:minutes:seconds.
Is there an easy way to convert the seconds to this format in Python?

You can use datetime.timedelta function:
>>> import datetime
>>> str(datetime.timedelta(seconds=666))
'0:11:06'

By using the divmod() function, which does only a single division to produce both the quotient and the remainder, you can have the result very quickly with only two mathematical operations:
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
And then use string formatting to convert the result into your desired output:
print('{:d}:{:02d}:{:02d}'.format(h, m, s)) # Python 3
print(f'{h:d}:{m:02d}:{s:02d}') # Python 3.6+

I can hardly name that an easy way (at least I can't remember the syntax), but it is possible to use time.strftime, which gives more control over formatting:
from time import strftime
from time import gmtime
strftime("%H:%M:%S", gmtime(666))
'00:11:06'
strftime("%H:%M:%S", gmtime(60*60*24))
'00:00:00'
gmtime is used to convert seconds to special tuple format that strftime() requires.
Note: Truncates after 23:59:59

Using datetime:
With the ':0>8' format:
from datetime import timedelta
"{:0>8}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{:0>8}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{:0>8}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Without the ':0>8' format:
"{}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Using time:
from time import gmtime
from time import strftime
# NOTE: The following resets if it goes over 23:59:59!
strftime("%H:%M:%S", gmtime(125))
# Result: '00:02:05'
strftime("%H:%M:%S", gmtime(60*60*24-1))
# Result: '23:59:59'
strftime("%H:%M:%S", gmtime(60*60*24))
# Result: '00:00:00'
strftime("%H:%M:%S", gmtime(666777))
# Result: '17:12:57'
# Wrong

This is my quick trick:
from humanfriendly import format_timespan
secondsPassed = 1302
format_timespan(secondsPassed)
# '21 minutes and 42 seconds'
For more info Visit:
https://humanfriendly.readthedocs.io/en/latest/api.html#humanfriendly.format_timespan

The following set worked for me.
def sec_to_hours(seconds):
a=str(seconds//3600)
b=str((seconds%3600)//60)
c=str((seconds%3600)%60)
d=["{} hours {} mins {} seconds".format(a, b, c)]
return d
print(sec_to_hours(10000))
# ['2 hours 46 mins 40 seconds']
print(sec_to_hours(60*60*24+105))
# ['24 hours 1 mins 45 seconds']

A bit off topic answer but maybe useful to someone
def time_format(seconds: int) -> str:
if seconds is not None:
seconds = int(seconds)
d = seconds // (3600 * 24)
h = seconds // 3600 % 24
m = seconds % 3600 // 60
s = seconds % 3600 % 60
if d > 0:
return '{:02d}D {:02d}H {:02d}m {:02d}s'.format(d, h, m, s)
elif h > 0:
return '{:02d}H {:02d}m {:02d}s'.format(h, m, s)
elif m > 0:
return '{:02d}m {:02d}s'.format(m, s)
elif s > 0:
return '{:02d}s'.format(s)
return '-'
Results in:
print(time_format(25*60*60 + 125))
>>> 01D 01H 02m 05s
print(time_format(17*60*60 + 35))
>>> 17H 00m 35s
print(time_format(3500))
>>> 58m 20s
print(time_format(21))
>>> 21s

This is how I got it.
def sec2time(sec, n_msec=3):
''' Convert seconds to 'D days, HH:MM:SS.FFF' '''
if hasattr(sec,'__len__'):
return [sec2time(s) for s in sec]
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
if n_msec > 0:
pattern = '%%02d:%%02d:%%0%d.%df' % (n_msec+3, n_msec)
else:
pattern = r'%02d:%02d:%02d'
if d == 0:
return pattern % (h, m, s)
return ('%d days, ' + pattern) % (d, h, m, s)
Some examples:
$ sec2time(10, 3)
Out: '00:00:10.000'
$ sec2time(1234567.8910, 0)
Out: '14 days, 06:56:07'
$ sec2time(1234567.8910, 4)
Out: '14 days, 06:56:07.8910'
$ sec2time([12, 345678.9], 3)
Out: ['00:00:12.000', '4 days, 00:01:18.900']

hours (h) calculated by floor division (by //) of seconds by 3600 (60 min/hr * 60 sec/min)
minutes (m) calculated by floor division of remaining seconds (remainder from hour calculation, by %) by 60 (60 sec/min)
similarly, seconds (s) by remainder of hour and minutes calculation.
Rest is just string formatting!
def hms(seconds):
h = seconds // 3600
m = seconds % 3600 // 60
s = seconds % 3600 % 60
return '{:02d}:{:02d}:{:02d}'.format(h, m, s)
print(hms(7500)) # Should print 02h05m00s

If you need to get datetime.time value, you can use this trick:
my_time = (datetime(1970,1,1) + timedelta(seconds=my_seconds)).time()
You cannot add timedelta to time, but can add it to datetime.
UPD: Yet another variation of the same technique:
my_time = (datetime.fromordinal(1) + timedelta(seconds=my_seconds)).time()
Instead of 1 you can use any number greater than 0. Here we use the fact that datetime.fromordinal will always return datetime object with time component being zero.

dateutil.relativedelta is convenient if you need to access hours, minutes and seconds as floats as well. datetime.timedelta does not provide a similar interface.
from dateutil.relativedelta import relativedelta
rt = relativedelta(seconds=5440)
print(rt.seconds)
print('{:02d}:{:02d}:{:02d}'.format(
int(rt.hours), int(rt.minutes), int(rt.seconds)))
Prints
40.0
01:30:40

Here is a way that I always use: (no matter how inefficient it is)
seconds = 19346
def zeroes (num):
if num < 10: num = "0" + num
return num
def return_hms(second, apply_zeroes):
sec = second % 60
min_ = second // 60 % 60
hrs = second // 3600
if apply_zeroes > 0:
sec = zeroes(sec)
min_ = zeroes(min_)
if apply_zeroes > 1:
hrs = zeroes(hrs)
return "{}:{}:{}".format(hrs, min_, sec)
print(return_hms(seconds, 1))
RESULT:
5:22:26
Syntax of return_hms() function
The return_hms() function is used like this:
The first variable (second) is the amount of seconds you want to convert into h:m:s.
The second variable (apply_zeroes) is formatting:
0 or less: Apply no zeroes whatsoever
1: Apply zeroes to minutes and seconds when they're below 10.
2 or more: Apply zeroes to any value (including hours) when they're below 10.

Here is a simple program that reads the current time and converts it to a time of day in hours, minutes, and seconds
import time as tm #import package time
timenow = tm.ctime() #fetch local time in string format
timeinhrs = timenow[11:19]
t=tm.time()#time.time() gives out time in seconds since epoch.
print("Time in HH:MM:SS format is: ",timeinhrs,"\nTime since epoch is : ",t/(3600*24),"days")
The output is
Time in HH:MM:SS format is: 13:32:45
Time since epoch is : 18793.335252338384 days

You can divide seconds by 60 to get the minutes
import time
seconds = time.time()
minutes = seconds / 60
print(minutes)
When you divide it by 60 again, you will get the hours

In my case I wanted to achieve format
"HH:MM:SS.fff".
I solved it like this:
timestamp = 28.97000002861023
str(datetime.fromtimestamp(timestamp)+timedelta(hours=-1)).split(' ')[1][:12]
'00:00:28.970'

The solutions above will work if you're looking to convert a single value for "seconds since midnight" on a date to a datetime object or a string with HH:MM:SS, but I landed on this page because I wanted to do this on a whole dataframe column in pandas. If anyone else is wondering how to do this for more than a single value at a time, what ended up working for me was:
mydate='2015-03-01'
df['datetime'] = datetime.datetime(mydate) + \
pandas.to_timedelta(df['seconds_since_midnight'], 's')

I looked every answers here and still tried my own
def a(t):
print(f"{int(t/3600)}H {int((t/60)%60) if t/3600>0 else int(t/60)}M {int(t%60)}S")
Results:
>>> a(7500)
2H 5M 0S
>>> a(3666)
1H 1M 6S
Python: 3.8.8

division = 3623 // 3600 #to hours
division2 = 600 // 60 #to minutes
print (division) #write hours
print (division2) #write minutes
PS My code is unprofessional

Related

Converting seconds to minutes and hours and writing to a CSV file [duplicate]

I have a function that returns information in seconds, but I need to store that information in hours:minutes:seconds.
Is there an easy way to convert the seconds to this format in Python?
You can use datetime.timedelta function:
>>> import datetime
>>> str(datetime.timedelta(seconds=666))
'0:11:06'
By using the divmod() function, which does only a single division to produce both the quotient and the remainder, you can have the result very quickly with only two mathematical operations:
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
And then use string formatting to convert the result into your desired output:
print('{:d}:{:02d}:{:02d}'.format(h, m, s)) # Python 3
print(f'{h:d}:{m:02d}:{s:02d}') # Python 3.6+
I can hardly name that an easy way (at least I can't remember the syntax), but it is possible to use time.strftime, which gives more control over formatting:
from time import strftime
from time import gmtime
strftime("%H:%M:%S", gmtime(666))
'00:11:06'
strftime("%H:%M:%S", gmtime(60*60*24))
'00:00:00'
gmtime is used to convert seconds to special tuple format that strftime() requires.
Note: Truncates after 23:59:59
Using datetime:
With the ':0>8' format:
from datetime import timedelta
"{:0>8}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{:0>8}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{:0>8}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Without the ':0>8' format:
"{}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Using time:
from time import gmtime
from time import strftime
# NOTE: The following resets if it goes over 23:59:59!
strftime("%H:%M:%S", gmtime(125))
# Result: '00:02:05'
strftime("%H:%M:%S", gmtime(60*60*24-1))
# Result: '23:59:59'
strftime("%H:%M:%S", gmtime(60*60*24))
# Result: '00:00:00'
strftime("%H:%M:%S", gmtime(666777))
# Result: '17:12:57'
# Wrong
This is my quick trick:
from humanfriendly import format_timespan
secondsPassed = 1302
format_timespan(secondsPassed)
# '21 minutes and 42 seconds'
For more info Visit:
https://humanfriendly.readthedocs.io/en/latest/api.html#humanfriendly.format_timespan
The following set worked for me.
def sec_to_hours(seconds):
a=str(seconds//3600)
b=str((seconds%3600)//60)
c=str((seconds%3600)%60)
d=["{} hours {} mins {} seconds".format(a, b, c)]
return d
print(sec_to_hours(10000))
# ['2 hours 46 mins 40 seconds']
print(sec_to_hours(60*60*24+105))
# ['24 hours 1 mins 45 seconds']
A bit off topic answer but maybe useful to someone
def time_format(seconds: int) -> str:
if seconds is not None:
seconds = int(seconds)
d = seconds // (3600 * 24)
h = seconds // 3600 % 24
m = seconds % 3600 // 60
s = seconds % 3600 % 60
if d > 0:
return '{:02d}D {:02d}H {:02d}m {:02d}s'.format(d, h, m, s)
elif h > 0:
return '{:02d}H {:02d}m {:02d}s'.format(h, m, s)
elif m > 0:
return '{:02d}m {:02d}s'.format(m, s)
elif s > 0:
return '{:02d}s'.format(s)
return '-'
Results in:
print(time_format(25*60*60 + 125))
>>> 01D 01H 02m 05s
print(time_format(17*60*60 + 35))
>>> 17H 00m 35s
print(time_format(3500))
>>> 58m 20s
print(time_format(21))
>>> 21s
This is how I got it.
def sec2time(sec, n_msec=3):
''' Convert seconds to 'D days, HH:MM:SS.FFF' '''
if hasattr(sec,'__len__'):
return [sec2time(s) for s in sec]
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
if n_msec > 0:
pattern = '%%02d:%%02d:%%0%d.%df' % (n_msec+3, n_msec)
else:
pattern = r'%02d:%02d:%02d'
if d == 0:
return pattern % (h, m, s)
return ('%d days, ' + pattern) % (d, h, m, s)
Some examples:
$ sec2time(10, 3)
Out: '00:00:10.000'
$ sec2time(1234567.8910, 0)
Out: '14 days, 06:56:07'
$ sec2time(1234567.8910, 4)
Out: '14 days, 06:56:07.8910'
$ sec2time([12, 345678.9], 3)
Out: ['00:00:12.000', '4 days, 00:01:18.900']
hours (h) calculated by floor division (by //) of seconds by 3600 (60 min/hr * 60 sec/min)
minutes (m) calculated by floor division of remaining seconds (remainder from hour calculation, by %) by 60 (60 sec/min)
similarly, seconds (s) by remainder of hour and minutes calculation.
Rest is just string formatting!
def hms(seconds):
h = seconds // 3600
m = seconds % 3600 // 60
s = seconds % 3600 % 60
return '{:02d}:{:02d}:{:02d}'.format(h, m, s)
print(hms(7500)) # Should print 02h05m00s
If you need to get datetime.time value, you can use this trick:
my_time = (datetime(1970,1,1) + timedelta(seconds=my_seconds)).time()
You cannot add timedelta to time, but can add it to datetime.
UPD: Yet another variation of the same technique:
my_time = (datetime.fromordinal(1) + timedelta(seconds=my_seconds)).time()
Instead of 1 you can use any number greater than 0. Here we use the fact that datetime.fromordinal will always return datetime object with time component being zero.
dateutil.relativedelta is convenient if you need to access hours, minutes and seconds as floats as well. datetime.timedelta does not provide a similar interface.
from dateutil.relativedelta import relativedelta
rt = relativedelta(seconds=5440)
print(rt.seconds)
print('{:02d}:{:02d}:{:02d}'.format(
int(rt.hours), int(rt.minutes), int(rt.seconds)))
Prints
40.0
01:30:40
Here is a way that I always use: (no matter how inefficient it is)
seconds = 19346
def zeroes (num):
if num < 10: num = "0" + num
return num
def return_hms(second, apply_zeroes):
sec = second % 60
min_ = second // 60 % 60
hrs = second // 3600
if apply_zeroes > 0:
sec = zeroes(sec)
min_ = zeroes(min_)
if apply_zeroes > 1:
hrs = zeroes(hrs)
return "{}:{}:{}".format(hrs, min_, sec)
print(return_hms(seconds, 1))
RESULT:
5:22:26
Syntax of return_hms() function
The return_hms() function is used like this:
The first variable (second) is the amount of seconds you want to convert into h:m:s.
The second variable (apply_zeroes) is formatting:
0 or less: Apply no zeroes whatsoever
1: Apply zeroes to minutes and seconds when they're below 10.
2 or more: Apply zeroes to any value (including hours) when they're below 10.
Here is a simple program that reads the current time and converts it to a time of day in hours, minutes, and seconds
import time as tm #import package time
timenow = tm.ctime() #fetch local time in string format
timeinhrs = timenow[11:19]
t=tm.time()#time.time() gives out time in seconds since epoch.
print("Time in HH:MM:SS format is: ",timeinhrs,"\nTime since epoch is : ",t/(3600*24),"days")
The output is
Time in HH:MM:SS format is: 13:32:45
Time since epoch is : 18793.335252338384 days
You can divide seconds by 60 to get the minutes
import time
seconds = time.time()
minutes = seconds / 60
print(minutes)
When you divide it by 60 again, you will get the hours
In my case I wanted to achieve format
"HH:MM:SS.fff".
I solved it like this:
timestamp = 28.97000002861023
str(datetime.fromtimestamp(timestamp)+timedelta(hours=-1)).split(' ')[1][:12]
'00:00:28.970'
The solutions above will work if you're looking to convert a single value for "seconds since midnight" on a date to a datetime object or a string with HH:MM:SS, but I landed on this page because I wanted to do this on a whole dataframe column in pandas. If anyone else is wondering how to do this for more than a single value at a time, what ended up working for me was:
mydate='2015-03-01'
df['datetime'] = datetime.datetime(mydate) + \
pandas.to_timedelta(df['seconds_since_midnight'], 's')
I looked every answers here and still tried my own
def a(t):
print(f"{int(t/3600)}H {int((t/60)%60) if t/3600>0 else int(t/60)}M {int(t%60)}S")
Results:
>>> a(7500)
2H 5M 0S
>>> a(3666)
1H 1M 6S
Python: 3.8.8
division = 3623 // 3600 #to hours
division2 = 600 // 60 #to minutes
print (division) #write hours
print (division2) #write minutes
PS My code is unprofessional

Formatting python timedelta result [duplicate]

I'm having trouble formatting a datetime.timedelta object.
Here's what I'm trying to do:
I have a list of objects and one of the members of the class of the object is a timedelta object that shows the duration of an event. I would like to display that duration in the format of hours:minutes.
I have tried a variety of methods for doing this and I'm having difficulty. My current approach is to add methods to the class for my objects that return hours and minutes. I can get the hours by dividing the timedelta.seconds by 3600 and rounding it. I'm having trouble with getting the remainder seconds and converting that to minutes.
By the way, I'm using Google AppEngine with Django Templates for presentation.
You can just convert the timedelta to a string with str(). Here's an example:
import datetime
start = datetime.datetime(2009,2,10,14,00)
end = datetime.datetime(2009,2,10,16,00)
delta = end-start
print(str(delta))
# prints 2:00:00
As you know, you can get the total_seconds from a timedelta object by accessing the .seconds attribute.
Python provides the builtin function divmod() which allows for:
s = 13420
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
print('{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
# result: 03:43:40
or you can convert to hours and remainder by using a combination of modulo and subtraction:
# arbitrary number of seconds
s = 13420
# hours
hours = s // 3600
# remaining seconds
s = s - (hours * 3600)
# minutes
minutes = s // 60
# remaining seconds
seconds = s - (minutes * 60)
# total time
print('{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
# result: 03:43:40
>>> str(datetime.timedelta(hours=10.56))
10:33:36
>>> td = datetime.timedelta(hours=10.505) # any timedelta object
>>> ':'.join(str(td).split(':')[:2])
10:30
Passing the timedelta object to the str() function calls the same formatting code used if we simply type print td. Since you don't want the seconds, we can split the string by colons (3 parts) and put it back together with only the first 2 parts.
def td_format(td_object):
seconds = int(td_object.total_seconds())
periods = [
('year', 60*60*24*365),
('month', 60*60*24*30),
('day', 60*60*24),
('hour', 60*60),
('minute', 60),
('second', 1)
]
strings=[]
for period_name, period_seconds in periods:
if seconds > period_seconds:
period_value , seconds = divmod(seconds, period_seconds)
has_s = 's' if period_value > 1 else ''
strings.append("%s %s%s" % (period_value, period_name, has_s))
return ", ".join(strings)
I personally use the humanize library for this:
>>> import datetime
>>> humanize.naturalday(datetime.datetime.now())
'today'
>>> humanize.naturalday(datetime.datetime.now() - datetime.timedelta(days=1))
'yesterday'
>>> humanize.naturalday(datetime.date(2007, 6, 5))
'Jun 05'
>>> humanize.naturaldate(datetime.date(2007, 6, 5))
'Jun 05 2007'
>>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=1))
'a second ago'
>>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=3600))
'an hour ago'
Of course, it doesn't give you exactly the answer you were looking for (which is, indeed, str(timeA - timeB), but I have found that once you go beyond a few hours, the display becomes quickly unreadable. humanize has support for much larger values that are human-readable, and is also well localized.
It's inspired by Django's contrib.humanize module, apparently, so since you are using Django, you should probably use that.
He already has a timedelta object so why not use its built-in method total_seconds() to convert it to seconds, then use divmod() to get hours and minutes?
hours, remainder = divmod(myTimeDelta.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
# Formatted only for hours and minutes as requested
print '%s:%s' % (hours, minutes)
This works regardless if the time delta has even days or years.
Here is a general purpose function for converting either a timedelta object or a regular number (in the form of seconds or minutes, etc.) to a nicely formatted string. I took mpounsett's fantastic answer on a duplicate question, made it a bit more flexible, improved readibility, and added documentation.
You will find that it is the most flexible answer here so far since it allows you to:
Customize the string format on the fly instead of it being hard-coded.
Leave out certain time intervals without a problem (see examples below).
Function:
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'):
"""Convert a datetime.timedelta object or a regular number to a custom-
formatted string, just like the stftime() method does for datetime.datetime
objects.
The fmt argument allows custom formatting to be specified. Fields can
include seconds, minutes, hours, days, and weeks. Each field is optional.
Some examples:
'{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default)
'{W}w {D}d {H}:{M:02}:{S:02}' --> '4w 5d 8:04:02'
'{D:2}d {H:2}:{M:02}:{S:02}' --> ' 5d 8:04:02'
'{H}h {S}s' --> '72h 800s'
The inputtype argument allows tdelta to be a regular number instead of the
default, which is a datetime.timedelta object. Valid inputtype strings:
's', 'seconds',
'm', 'minutes',
'h', 'hours',
'd', 'days',
'w', 'weeks'
"""
# Convert tdelta to integer seconds.
if inputtype == 'timedelta':
remainder = int(tdelta.total_seconds())
elif inputtype in ['s', 'seconds']:
remainder = int(tdelta)
elif inputtype in ['m', 'minutes']:
remainder = int(tdelta)*60
elif inputtype in ['h', 'hours']:
remainder = int(tdelta)*3600
elif inputtype in ['d', 'days']:
remainder = int(tdelta)*86400
elif inputtype in ['w', 'weeks']:
remainder = int(tdelta)*604800
f = Formatter()
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
possible_fields = ('W', 'D', 'H', 'M', 'S')
constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
values = {}
for field in possible_fields:
if field in desired_fields and field in constants:
values[field], remainder = divmod(remainder, constants[field])
return f.format(fmt, **values)
Demo:
>>> td = timedelta(days=2, hours=3, minutes=5, seconds=8, microseconds=340)
>>> print strfdelta(td)
02d 03h 05m 08s
>>> print strfdelta(td, '{D}d {H}:{M:02}:{S:02}')
2d 3:05:08
>>> print strfdelta(td, '{D:2}d {H:2}:{M:02}:{S:02}')
2d 3:05:08
>>> print strfdelta(td, '{H}h {S}s')
51h 308s
>>> print strfdelta(12304, inputtype='s')
00d 03h 25m 04s
>>> print strfdelta(620, '{H}:{M:02}', 'm')
10:20
>>> print strfdelta(49, '{D}d {H}h', 'h')
2d 1h
I know that this is an old answered question, but I use datetime.utcfromtimestamp() for this. It takes the number of seconds and returns a datetime that can be formatted like any other datetime.
duration = datetime.utcfromtimestamp(end - begin)
print duration.strftime('%H:%M')
As long as you stay in the legal ranges for the time parts this should work, i.e. it doesn't return 1234:35 as hours are <= 23.
maybe:
>>> import datetime
>>> dt0 = datetime.datetime(1,1,1)
>>> td = datetime.timedelta(minutes=34, hours=12, seconds=56)
>>> (dt0+td).strftime('%X')
'12:34:56'
>>> (dt0+td).strftime('%M:%S')
'34:56'
>>> (dt0+td).strftime('%H:%M')
'12:34'
>>>
I would seriously consider the Occam's Razor approach here:
td = str(timedelta).split('.')[0]
This returns a string without the microseconds
If you want to regenerate the datetime.timedelta object, just do this:
h,m,s = re.split(':', td)
new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s))
2 years in, I love this language!
I used the humanfriendly python library to do this, it works very well.
import humanfriendly
from datetime import timedelta
delta = timedelta(seconds = 321)
humanfriendly.format_timespan(delta)
'5 minutes and 21 seconds'
Available at https://pypi.org/project/humanfriendly/
Questioner wants a nicer format than the typical:
>>> import datetime
>>> datetime.timedelta(seconds=41000)
datetime.timedelta(0, 41000)
>>> str(datetime.timedelta(seconds=41000))
'11:23:20'
>>> str(datetime.timedelta(seconds=4102.33))
'1:08:22.330000'
>>> str(datetime.timedelta(seconds=413302.33))
'4 days, 18:48:22.330000'
So, really there's two formats, one where days are 0 and it's left out, and another where there's text "n days, h:m:s". But, the seconds may have fractions, and there's no leading zeroes in the printouts, so columns are messy.
Here's my routine, if you like it:
def printNiceTimeDelta(stime, etime):
delay = datetime.timedelta(seconds=(etime - stime))
if (delay.days > 0):
out = str(delay).replace(" days, ", ":")
else:
out = "0:" + str(delay)
outAr = out.split(':')
outAr = ["%02d" % (int(float(x))) for x in outAr]
out = ":".join(outAr)
return out
this returns output as dd:hh:mm:ss format:
00:00:00:15
00:00:00:19
02:01:31:40
02:01:32:22
I did think about adding years to this, but this is left as an exercise for the reader, since the output is safe at over 1 year:
>>> str(datetime.timedelta(seconds=99999999))
'1157 days, 9:46:39'
My datetime.timedelta objects went greater than a day. So here is a further problem. All the discussion above assumes less than a day. A timedelta is actually a tuple of days, seconds and microseconds. The above discussion should use td.seconds as joe did, but if you have days it is NOT included in the seconds value.
I am getting a span of time between 2 datetimes and printing days and hours.
span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)
I have a function:
def period(delta, pattern):
d = {'d': delta.days}
d['h'], rem = divmod(delta.seconds, 3600)
d['m'], d['s'] = divmod(rem, 60)
return pattern.format(**d)
Examples:
>>> td = timedelta(seconds=123456789)
>>> period(td, "{d} days {h}:{m}:{s}")
'1428 days 21:33:9'
>>> period(td, "{h} hours, {m} minutes and {s} seconds, {d} days")
'21 hours, 33 minutes and 9 seconds, 1428 days'
Following Joe's example value above, I'd use the modulus arithmetic operator, thusly:
td = datetime.timedelta(hours=10.56)
td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60)
Note that integer division in Python rounds down by default; if you want to be more explicit, use math.floor() or math.ceil() as appropriate.
One liner. Since timedeltas do not offer datetime's strftime, bring the timedelta back to a datetime, and use stftime.
This can not only achieve the OP's requested format Hours:Minutes, now you can leverage the full formatting power of datetime's strftime, should your requirements change to another representation.
import datetime
td = datetime.timedelta(hours=2, minutes=10, seconds=5)
print(td)
print(datetime.datetime.strftime(datetime.datetime.strptime(str(td), "%H:%M:%S"), "%H:%M"))
Output:
2:10:05
02:10
This also solves the annoyance that timedeltas are formatted into strings as H:MM:SS rather than HH:MM:SS, which lead me to this problem, and the solution I've shared.
import datetime
hours = datetime.timedelta(hours=16, minutes=30)
print((datetime.datetime(1,1,1) + hours).strftime('%H:%M'))
def seconds_to_time_left_string(total_seconds):
s = int(total_seconds)
years = s // 31104000
if years > 1:
return '%d years' % years
s = s - (years * 31104000)
months = s // 2592000
if years == 1:
r = 'one year'
if months > 0:
r += ' and %d months' % months
return r
if months > 1:
return '%d months' % months
s = s - (months * 2592000)
days = s // 86400
if months == 1:
r = 'one month'
if days > 0:
r += ' and %d days' % days
return r
if days > 1:
return '%d days' % days
s = s - (days * 86400)
hours = s // 3600
if days == 1:
r = 'one day'
if hours > 0:
r += ' and %d hours' % hours
return r
s = s - (hours * 3600)
minutes = s // 60
seconds = s - (minutes * 60)
if hours >= 6:
return '%d hours' % hours
if hours >= 1:
r = '%d hours' % hours
if hours == 1:
r = 'one hour'
if minutes > 0:
r += ' and %d minutes' % minutes
return r
if minutes == 1:
r = 'one minute'
if seconds > 0:
r += ' and %d seconds' % seconds
return r
if minutes == 0:
return '%d seconds' % seconds
if seconds == 0:
return '%d minutes' % minutes
return '%d minutes and %d seconds' % (minutes, seconds)
for i in range(10):
print pow(8, i), seconds_to_time_left_string(pow(8, i))
Output:
1 1 seconds
8 8 seconds
64 one minute and 4 seconds
512 8 minutes and 32 seconds
4096 one hour and 8 minutes
32768 9 hours
262144 3 days
2097152 24 days
16777216 6 months
134217728 4 years
I had a similar problem with the output of overtime calculation at work. The value should always show up in HH:MM, even when it is greater than one day and the value can get negative. I combined some of the shown solutions and maybe someone else find this solution useful. I realized that if the timedelta value is negative most of the shown solutions with the divmod method doesn't work out of the box:
def td2HHMMstr(td):
'''Convert timedelta objects to a HH:MM string with (+/-) sign'''
if td < datetime.timedelta(seconds=0):
sign='-'
td = -td
else:
sign = ''
tdhours, rem = divmod(td.total_seconds(), 3600)
tdminutes, rem = divmod(rem, 60)
tdstr = '{}{:}:{:02d}'.format(sign, int(tdhours), int(tdminutes))
return tdstr
timedelta to HH:MM string:
td2HHMMstr(datetime.timedelta(hours=1, minutes=45))
'1:54'
td2HHMMstr(datetime.timedelta(days=2, hours=3, minutes=2))
'51:02'
td2HHMMstr(datetime.timedelta(hours=-3, minutes=-2))
'-3:02'
td2HHMMstr(datetime.timedelta(days=-35, hours=-3, minutes=-2))
'-843:02'
from django.utils.translation import ngettext
def localize_timedelta(delta):
ret = []
num_years = int(delta.days / 365)
if num_years > 0:
delta -= timedelta(days=num_years * 365)
ret.append(ngettext('%d year', '%d years', num_years) % num_years)
if delta.days > 0:
ret.append(ngettext('%d day', '%d days', delta.days) % delta.days)
num_hours = int(delta.seconds / 3600)
if num_hours > 0:
delta -= timedelta(hours=num_hours)
ret.append(ngettext('%d hour', '%d hours', num_hours) % num_hours)
num_minutes = int(delta.seconds / 60)
if num_minutes > 0:
ret.append(ngettext('%d minute', '%d minutes', num_minutes) % num_minutes)
return ' '.join(ret)
This will produce:
>>> from datetime import timedelta
>>> localize_timedelta(timedelta(days=3660, minutes=500))
'10 years 10 days 8 hours 20 minutes'
A straight forward template filter for this problem. The built-in function int() never rounds up. F-Strings (i.e. f'') require python 3.6.
#app_template_filter()
def diffTime(end, start):
diff = (end - start).total_seconds()
d = int(diff / 86400)
h = int((diff - (d * 86400)) / 3600)
m = int((diff - (d * 86400 + h * 3600)) / 60)
s = int((diff - (d * 86400 + h * 3600 + m *60)))
if d > 0:
fdiff = f'{d}d {h}h {m}m {s}s'
elif h > 0:
fdiff = f'{h}h {m}m {s}s'
elif m > 0:
fdiff = f'{m}m {s}s'
else:
fdiff = f'{s}s'
return fdiff
If you happen to have IPython in your packages (you should), it has (up to now, anyway) a very nice formatter for durations (in float seconds). That is used in various places, for example by the %%time cell magic. I like the format it produces for short durations:
>>> from IPython.core.magics.execution import _format_time
>>>
>>> for v in range(-9, 10, 2):
... dt = 1.25 * 10**v
... print(_format_time(dt))
1.25 ns
125 ns
12.5 µs
1.25 ms
125 ms
12.5 s
20min 50s
1d 10h 43min 20s
144d 16h 13min 20s
14467d 14h 13min 20s
I continued from MarredCheese's answer and added year, month, millicesond and microsecond
all numbers are formatted to integer except for second, thus the fraction of a second can be customized.
#kfmfe04 asked for fraction of a second so I posted this solution
In the main there are some examples.
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02.0f}s', inputtype='timedelta'):
"""Convert a datetime.timedelta object or a regular number to a custom-
formatted string, just like the stftime() method does for datetime.datetime
objects.
The fmt argument allows custom formatting to be specified. Fields can
include seconds, minutes, hours, days, and weeks. Each field is optional.
Some examples:
'{D:02}d {H:02}h {M:02}m {S:02.0f}s' --> '05d 08h 04m 02s' (default)
'{W}w {D}d {H}:{M:02}:{S:02.0f}' --> '4w 5d 8:04:02'
'{D:2}d {H:2}:{M:02}:{S:02.0f}' --> ' 5d 8:04:02'
'{H}h {S:.0f}s' --> '72h 800s'
The inputtype argument allows tdelta to be a regular number instead of the
default, which is a datetime.timedelta object. Valid inputtype strings:
's', 'seconds',
'm', 'minutes',
'h', 'hours',
'd', 'days',
'w', 'weeks'
"""
# Convert tdelta to integer seconds.
if inputtype == 'timedelta':
remainder = tdelta.total_seconds()
elif inputtype in ['s', 'seconds']:
remainder = float(tdelta)
elif inputtype in ['m', 'minutes']:
remainder = float(tdelta)*60
elif inputtype in ['h', 'hours']:
remainder = float(tdelta)*3600
elif inputtype in ['d', 'days']:
remainder = float(tdelta)*86400
elif inputtype in ['w', 'weeks']:
remainder = float(tdelta)*604800
f = Formatter()
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
possible_fields = ('Y','m','W', 'D', 'H', 'M', 'S', 'mS', 'µS')
constants = {'Y':86400*365.24,'m': 86400*30.44 ,'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1, 'mS': 1/pow(10,3) , 'µS':1/pow(10,6)}
values = {}
for field in possible_fields:
if field in desired_fields and field in constants:
Quotient, remainder = divmod(remainder, constants[field])
values[field] = int(Quotient) if field != 'S' else Quotient + remainder
return f.format(fmt, **values)
if __name__ == "__main__":
td = timedelta(days=717, hours=3, minutes=5, seconds=8, microseconds=3549)
print(strfdelta(td,'{Y} years {m} months {W} weeks {D} days {H:02}:{M:02}:{S:02}'))
print(strfdelta(td,'{m} months {W} weeks {D} days {H:02}:{M:02}:{S:02.4f}'))
td = timedelta( seconds=8, microseconds=8549)
print(strfdelta(td,'{S} seconds {mS} milliseconds {µS} microseconds'))
print(strfdelta(td,'{S:.0f} seconds {mS} milliseconds {µS} microseconds'))
print(strfdelta(pow(10,7),inputtype='s'))
Output:
1 years 11 months 2 weeks 3 days 01:09:56.00354900211096
23 months 2 weeks 3 days 00:12:20.0035
8.008549 seconds 8 milliseconds 549 microseconds
8 seconds 8 milliseconds 549 microseconds
115d 17h 46m 40s
Here's a function to stringify timedelta.total_seconds(). It works in python 2 and 3.
def strf_interval(seconds):
days, remainder = divmod(seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
return '{} {} {} {}'.format(
"" if int(days) == 0 else str(int(days)) + ' days',
"" if int(hours) == 0 else str(int(hours)) + ' hours',
"" if int(minutes) == 0 else str(int(minutes)) + ' mins',
"" if int(seconds) == 0 else str(int(seconds)) + ' secs'
)
Example output:
>>> print(strf_interval(1))
1 secs
>>> print(strf_interval(100))
1 mins 40 secs
>>> print(strf_interval(1000))
16 mins 40 secs
>>> print(strf_interval(10000))
2 hours 46 mins 40 secs
>>> print(strf_interval(100000))
1 days 3 hours 46 mins 40 secs
timedelta to string, use for print running time info.
def strfdelta_round(tdelta, round_period='second'):
"""timedelta to string, use for measure running time
attend period from days downto smaller period, round to minimum period
omit zero value period
"""
period_names = ('day', 'hour', 'minute', 'second', 'millisecond')
if round_period not in period_names:
raise Exception(f'round_period "{round_period}" invalid, should be one of {",".join(period_names)}')
period_seconds = (86400, 3600, 60, 1, 1/pow(10,3))
period_desc = ('days', 'hours', 'mins', 'secs', 'msecs')
round_i = period_names.index(round_period)
s = ''
remainder = tdelta.total_seconds()
for i in range(len(period_names)):
q, remainder = divmod(remainder, period_seconds[i])
if int(q)>0:
if not len(s)==0:
s += ' '
s += f'{q:.0f} {period_desc[i]}'
if i==round_i:
break
if i==round_i+1:
s += f'{remainder} {period_desc[round_i]}'
break
return s
e.g. auto omit zero leading period:
>>> td = timedelta(days=0, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'second')
'2 hours 5 mins 8 secs'
or omit middle zero period:
>>> td = timedelta(days=2, hours=0, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'millisecond')
'2 days 5 mins 8 secs 3 msecs'
or round to minutes, omit below minutes:
>>> td = timedelta(days=1, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'minute')
'1 days 2 hours 5 mins'
Please check this function - it converts timedelta object into string 'HH:MM:SS'
def format_timedelta(td):
hours, remainder = divmod(td.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
hours, minutes, seconds = int(hours), int(minutes), int(seconds)
if hours < 10:
hours = '0%s' % int(hours)
if minutes < 10:
minutes = '0%s' % minutes
if seconds < 10:
seconds = '0%s' % seconds
return '%s:%s:%s' % (hours, minutes, seconds)
If you already have a timedelta obj then just convert that obj into string. Remove the last 3 characters of the string and print. This will truncate the seconds part and print the rest of it in the format Hours:Minutes.
t = str(timedeltaobj)
print t[:-3]
I wanted to do this so wrote a simple function. It works great for me and is quite versatile (supports years to microseconds, and any granularity level, e.g. you can pick between '2 days, 4 hours, 48 minutes' and '2 days, 4 hours' and '2 days, 4.8 hours', etc.
def pretty_print_timedelta(t, max_components=None, max_decimal_places=2):
'''
Print a pretty string for a timedelta.
For example datetime.timedelta(days=2, seconds=17280) will be printed as '2 days, 4 hours, 48 minutes'. Setting max_components to e.g. 1 will change this to '2.2 days', where the
number of decimal points can also be set.
'''
time_scales = [timedelta(days=365), timedelta(days=1), timedelta(hours=1), timedelta(minutes=1), timedelta(seconds=1), timedelta(microseconds=1000), timedelta(microseconds=1)]
time_scale_names_dict = {timedelta(days=365): 'year',
timedelta(days=1): 'day',
timedelta(hours=1): 'hour',
timedelta(minutes=1): 'minute',
timedelta(seconds=1): 'second',
timedelta(microseconds=1000): 'millisecond',
timedelta(microseconds=1): 'microsecond'}
count = 0
txt = ''
first = True
for scale in time_scales:
if t >= scale:
count += 1
if count == max_components:
n = t / scale
else:
n = int(t / scale)
t -= n*scale
n_txt = str(round(n, max_decimal_places))
if n_txt[-2:]=='.0': n_txt = n_txt[:-2]
txt += '{}{} {}{}'.format('' if first else ', ', n_txt, time_scale_names_dict[scale], 's' if n>1 else '', )
if first:
first = False
if len(txt) == 0:
txt = 'none'
return txt
I had the same problem and I am using pandas Timedeltas, didn't want to bring in additional dependencies (another answer mentions humanfriendly) so I wrote this small function to print out only the relevant information:
def format_timedelta(td: pd.Timedelta) -> str:
if pd.isnull(td):
return str(td)
else:
c = td.components._asdict()
return ", ".join(f"{n} {unit}" for unit, n in c.items() if n)
For example, pd.Timedelta(hours=3, seconds=12) would print as 3 hours, 12 seconds.
I suggest the following method so that we can utilize the standard formatting function, pandas.Timestamp.strftime!
from pandas import Timestamp, Timedelta
(Timedelta("2 hours 30 min") + Timestamp("00:00:00")).strftime("%H:%M")

How to convert an H:MM:SS time string to seconds in Python?

Basically I have the inverse of this problem: Python Time Seconds to h:m:s
I have a string in the format H:MM:SS (always 2 digits for minutes and seconds), and I need the integer number of seconds that it represents. How can I do this in python?
For example:
"1:23:45" would produce an output of 5025
"0:04:15" would produce an output of 255
"0:00:25" would produce an output of 25
etc
def get_sec(time_str):
"""Get seconds from time."""
h, m, s = time_str.split(':')
return int(h) * 3600 + int(m) * 60 + int(s)
print(get_sec('1:23:45'))
print(get_sec('0:04:15'))
print(get_sec('0:00:25'))
ts = '1:23:45'
secs = sum(int(x) * 60 ** i for i, x in enumerate(reversed(ts.split(':'))))
print(secs)
Using datetime module
import datetime
t = '10:15:30'
h,m,s = t.split(':')
print(int(datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s)).total_seconds()))
Output: 36930
Without many checks, and assuming it's either "SS" or "MM:SS" or "HH:MM:SS" (although not necessarily two digits per part):
def to_seconds(timestr):
seconds= 0
for part in timestr.split(':'):
seconds= seconds*60 + int(part, 10)
return seconds
>>> to_seconds('09')
9
>>> to_seconds('2:09')
129
>>> to_seconds('1:02:09')
3729
This is a different “spelling” of FMc's answer :)
Using datetime module is also posible and more robust
import datetime as dt
def get_total_seconds(stringHMS):
timedeltaObj = dt.datetime.strptime(stringHMS, "%H:%M:%S") - dt.datetime(1900,1,1)
return timedeltaObj.total_seconds()
datetime.strptime parses the string according to format %H:%M:%S, and it creates a datetime object as year 1900, month1, day 1, hour H, minute M, and second S.
That's why to get the total of seconds is necessary to subtract the year, month and day.
print(get_total_seconds('1:23:45'))
>>> 5025.0
print(get_total_seconds('0:04:15'))
>>> 255.0
print(get_total_seconds('0:00:25'))
>>>25.0
You can use lambda and reduce a list and the fact that m=60s and h=60m. (see "Reducing a List" at http://www.python-course.eu/lambda.php)
timestamp = "1:23:45"
seconds = reduce(lambda x, y: x*60+y, [int(i) for i in (timestamp.replace(':',',')).split(',')])
You can split the time into a list and add each individual time component, multiplying the hours component by 3600 (the number of seconds in an hour) and the minutes component by 60 (number of seconds in a minute), like:
timeInterval ='00:35:01'
list = timeInterval.split(':')
hours = list[0]
minutes = list[1]
seconds = list[2]
total = (int(hours) * 3600 + int(minutes) * 60 + int(seconds))
print("total = ", total)
For %H:%M:%S.%f
def get_sec(time_str):
h, m, s = time_str.split(':')
return int(h) * 3600 + int(m) * 60 + float(s)
parts = time_string.split(":")
seconds = int(parts[0])*(60*60) + int(parts[1])*60 + int(parts[2])
I didn't really like any of the given answers, so I used the following:
def timestamp_to_seconds(t):
return sum(float(n) * m for n,
m in zip(reversed(time.split(':')), (1, 60, 3600))
)
Expanding on #FMc's solution which embodies half of Horner's method. Advantage of Horner's method: Skip reversing the list, avoid power calculation.
from functools import reduce
timestamp = "1:23:45"
seconds = reduce(lambda s, d: s * 60 + int(d), timestamp.split(":"), 0)
or, if you dislike reduce (as does Guido van Rossum and #0xc0de below):
timestamp = "1:23:45"
seconds = 0
for d in timestamp.split(":"):
seconds = seconds * 60 + int(d)
If you prefer zip (as does #nathan-rice below):
from itertools import accumulate, repeat
from operator import mul
def timestamp_to_seconds(t):
return sum(int(n) * m for n, m in
zip(reversed(t.split(":")), accumulate(repeat(60), func=mul, initial=1)))
Another alternative if you have days on string:
def duration2sec(string):
if "days" in string:
days = string.split()[0]
hours = string.split()[2].split(':')
return int(days) * 86400 + int(hours[0]) * 3600 + int(hours[1]) * 60 + int(hours[2])
else:
hours = string.split(':')
return int(hours[0]) * 3600 + int(hours[1]) * 60 + int(hours[2])
Just a simple generalization to the great response of taskinoor
In the context of my problem the format is similar, but includes AM or PM.
Format 'HH:MM:SS AM' or 'HH:MM:SS PM'
For this case the function changes to:
def get_sec(time_str):
"""Get Seconds from time."""
if 'AM' in time_str:
time_str = time_str.strip('AM')
h, m, s = time_str.split(':')
seconds = int(h) * 3600 + int(m) * 60 + int(s)
if 'PM' in time_str:
time_str = time_str.strip('PM')
h, m, s = time_str.split(':')
seconds = (12 + int(h)) * 3600 + int(m) * 60 + int(s)
return seconds
In Pandas using #JayRizzo 's cool function and a list comprehension:
def get_sec(time_str):
"""Get Seconds from time."""
h, m, s = time_str.split(':')
return int(h) * 3600 + int(m) * 60 + int(s)
df['secs']=[get_sec(x) for x in df['original_time_string']]
I liked tzot's answer above the best for my purposes because my H:M:S are human created and the can have float seconds part
Here is my small modification
def hms_to_seconds(timestr:str)->float:
"""Get seconds from time.
:param timestr: hh:mm:ss.xxx string or mm:s.xxx or simply s.xxx where xxx is the fraction of seconds
:returns: time in float seconds
"""
seconds= 0.
for part in timestr.split(':'):
seconds= seconds*60. + float(part)
return seconds
>>> hms_to_seconds('3.00')
3.0
>>> hms_to_seconds('1:3.00')
63.0
>>> hms_to_seconds('1:0:3.5')
3603.5

Convert seconds to hh:mm:ss in Python [duplicate]

This question already has answers here:
How do I convert seconds to hours, minutes and seconds?
(18 answers)
Closed 9 years ago.
How do I convert an int (number of seconds) to the formats mm:ss or hh:mm:ss?
I need to do this with Python code (and if possible in a Django template).
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.
>>> a = datetime.timedelta(seconds=65)
datetime.timedelta(0, 65)
>>> str(a)
'0:01:05'
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'
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.
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.
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
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
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
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
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

Format timedelta to string

I'm having trouble formatting a datetime.timedelta object.
Here's what I'm trying to do:
I have a list of objects and one of the members of the class of the object is a timedelta object that shows the duration of an event. I would like to display that duration in the format of hours:minutes.
I have tried a variety of methods for doing this and I'm having difficulty. My current approach is to add methods to the class for my objects that return hours and minutes. I can get the hours by dividing the timedelta.seconds by 3600 and rounding it. I'm having trouble with getting the remainder seconds and converting that to minutes.
By the way, I'm using Google AppEngine with Django Templates for presentation.
You can just convert the timedelta to a string with str(). Here's an example:
import datetime
start = datetime.datetime(2009,2,10,14,00)
end = datetime.datetime(2009,2,10,16,00)
delta = end-start
print(str(delta))
# prints 2:00:00
As you know, you can get the total_seconds from a timedelta object by accessing the .seconds attribute.
Python provides the builtin function divmod() which allows for:
s = 13420
hours, remainder = divmod(s, 3600)
minutes, seconds = divmod(remainder, 60)
print('{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
# result: 03:43:40
or you can convert to hours and remainder by using a combination of modulo and subtraction:
# arbitrary number of seconds
s = 13420
# hours
hours = s // 3600
# remaining seconds
s = s - (hours * 3600)
# minutes
minutes = s // 60
# remaining seconds
seconds = s - (minutes * 60)
# total time
print('{:02}:{:02}:{:02}'.format(int(hours), int(minutes), int(seconds)))
# result: 03:43:40
>>> str(datetime.timedelta(hours=10.56))
10:33:36
>>> td = datetime.timedelta(hours=10.505) # any timedelta object
>>> ':'.join(str(td).split(':')[:2])
10:30
Passing the timedelta object to the str() function calls the same formatting code used if we simply type print td. Since you don't want the seconds, we can split the string by colons (3 parts) and put it back together with only the first 2 parts.
def td_format(td_object):
seconds = int(td_object.total_seconds())
periods = [
('year', 60*60*24*365),
('month', 60*60*24*30),
('day', 60*60*24),
('hour', 60*60),
('minute', 60),
('second', 1)
]
strings=[]
for period_name, period_seconds in periods:
if seconds > period_seconds:
period_value , seconds = divmod(seconds, period_seconds)
has_s = 's' if period_value > 1 else ''
strings.append("%s %s%s" % (period_value, period_name, has_s))
return ", ".join(strings)
I personally use the humanize library for this:
>>> import datetime
>>> humanize.naturalday(datetime.datetime.now())
'today'
>>> humanize.naturalday(datetime.datetime.now() - datetime.timedelta(days=1))
'yesterday'
>>> humanize.naturalday(datetime.date(2007, 6, 5))
'Jun 05'
>>> humanize.naturaldate(datetime.date(2007, 6, 5))
'Jun 05 2007'
>>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=1))
'a second ago'
>>> humanize.naturaltime(datetime.datetime.now() - datetime.timedelta(seconds=3600))
'an hour ago'
Of course, it doesn't give you exactly the answer you were looking for (which is, indeed, str(timeA - timeB), but I have found that once you go beyond a few hours, the display becomes quickly unreadable. humanize has support for much larger values that are human-readable, and is also well localized.
It's inspired by Django's contrib.humanize module, apparently, so since you are using Django, you should probably use that.
He already has a timedelta object so why not use its built-in method total_seconds() to convert it to seconds, then use divmod() to get hours and minutes?
hours, remainder = divmod(myTimeDelta.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
# Formatted only for hours and minutes as requested
print '%s:%s' % (hours, minutes)
This works regardless if the time delta has even days or years.
Here is a general purpose function for converting either a timedelta object or a regular number (in the form of seconds or minutes, etc.) to a nicely formatted string. I took mpounsett's fantastic answer on a duplicate question, made it a bit more flexible, improved readibility, and added documentation.
You will find that it is the most flexible answer here so far since it allows you to:
Customize the string format on the fly instead of it being hard-coded.
Leave out certain time intervals without a problem (see examples below).
Function:
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02}s', inputtype='timedelta'):
"""Convert a datetime.timedelta object or a regular number to a custom-
formatted string, just like the stftime() method does for datetime.datetime
objects.
The fmt argument allows custom formatting to be specified. Fields can
include seconds, minutes, hours, days, and weeks. Each field is optional.
Some examples:
'{D:02}d {H:02}h {M:02}m {S:02}s' --> '05d 08h 04m 02s' (default)
'{W}w {D}d {H}:{M:02}:{S:02}' --> '4w 5d 8:04:02'
'{D:2}d {H:2}:{M:02}:{S:02}' --> ' 5d 8:04:02'
'{H}h {S}s' --> '72h 800s'
The inputtype argument allows tdelta to be a regular number instead of the
default, which is a datetime.timedelta object. Valid inputtype strings:
's', 'seconds',
'm', 'minutes',
'h', 'hours',
'd', 'days',
'w', 'weeks'
"""
# Convert tdelta to integer seconds.
if inputtype == 'timedelta':
remainder = int(tdelta.total_seconds())
elif inputtype in ['s', 'seconds']:
remainder = int(tdelta)
elif inputtype in ['m', 'minutes']:
remainder = int(tdelta)*60
elif inputtype in ['h', 'hours']:
remainder = int(tdelta)*3600
elif inputtype in ['d', 'days']:
remainder = int(tdelta)*86400
elif inputtype in ['w', 'weeks']:
remainder = int(tdelta)*604800
f = Formatter()
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
possible_fields = ('W', 'D', 'H', 'M', 'S')
constants = {'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1}
values = {}
for field in possible_fields:
if field in desired_fields and field in constants:
values[field], remainder = divmod(remainder, constants[field])
return f.format(fmt, **values)
Demo:
>>> td = timedelta(days=2, hours=3, minutes=5, seconds=8, microseconds=340)
>>> print strfdelta(td)
02d 03h 05m 08s
>>> print strfdelta(td, '{D}d {H}:{M:02}:{S:02}')
2d 3:05:08
>>> print strfdelta(td, '{D:2}d {H:2}:{M:02}:{S:02}')
2d 3:05:08
>>> print strfdelta(td, '{H}h {S}s')
51h 308s
>>> print strfdelta(12304, inputtype='s')
00d 03h 25m 04s
>>> print strfdelta(620, '{H}:{M:02}', 'm')
10:20
>>> print strfdelta(49, '{D}d {H}h', 'h')
2d 1h
I know that this is an old answered question, but I use datetime.utcfromtimestamp() for this. It takes the number of seconds and returns a datetime that can be formatted like any other datetime.
duration = datetime.utcfromtimestamp(end - begin)
print duration.strftime('%H:%M')
As long as you stay in the legal ranges for the time parts this should work, i.e. it doesn't return 1234:35 as hours are <= 23.
I would seriously consider the Occam's Razor approach here:
td = str(timedelta).split('.')[0]
This returns a string without the microseconds
If you want to regenerate the datetime.timedelta object, just do this:
h,m,s = re.split(':', td)
new_delta = datetime.timedelta(hours=int(h),minutes=int(m),seconds=int(s))
2 years in, I love this language!
maybe:
>>> import datetime
>>> dt0 = datetime.datetime(1,1,1)
>>> td = datetime.timedelta(minutes=34, hours=12, seconds=56)
>>> (dt0+td).strftime('%X')
'12:34:56'
>>> (dt0+td).strftime('%M:%S')
'34:56'
>>> (dt0+td).strftime('%H:%M')
'12:34'
>>>
I used the humanfriendly python library to do this, it works very well.
import humanfriendly
from datetime import timedelta
delta = timedelta(seconds = 321)
humanfriendly.format_timespan(delta)
'5 minutes and 21 seconds'
Available at https://pypi.org/project/humanfriendly/
Questioner wants a nicer format than the typical:
>>> import datetime
>>> datetime.timedelta(seconds=41000)
datetime.timedelta(0, 41000)
>>> str(datetime.timedelta(seconds=41000))
'11:23:20'
>>> str(datetime.timedelta(seconds=4102.33))
'1:08:22.330000'
>>> str(datetime.timedelta(seconds=413302.33))
'4 days, 18:48:22.330000'
So, really there's two formats, one where days are 0 and it's left out, and another where there's text "n days, h:m:s". But, the seconds may have fractions, and there's no leading zeroes in the printouts, so columns are messy.
Here's my routine, if you like it:
def printNiceTimeDelta(stime, etime):
delay = datetime.timedelta(seconds=(etime - stime))
if (delay.days > 0):
out = str(delay).replace(" days, ", ":")
else:
out = "0:" + str(delay)
outAr = out.split(':')
outAr = ["%02d" % (int(float(x))) for x in outAr]
out = ":".join(outAr)
return out
this returns output as dd:hh:mm:ss format:
00:00:00:15
00:00:00:19
02:01:31:40
02:01:32:22
I did think about adding years to this, but this is left as an exercise for the reader, since the output is safe at over 1 year:
>>> str(datetime.timedelta(seconds=99999999))
'1157 days, 9:46:39'
My datetime.timedelta objects went greater than a day. So here is a further problem. All the discussion above assumes less than a day. A timedelta is actually a tuple of days, seconds and microseconds. The above discussion should use td.seconds as joe did, but if you have days it is NOT included in the seconds value.
I am getting a span of time between 2 datetimes and printing days and hours.
span = currentdt - previousdt
print '%d,%d\n' % (span.days,span.seconds/3600)
I have a function:
def period(delta, pattern):
d = {'d': delta.days}
d['h'], rem = divmod(delta.seconds, 3600)
d['m'], d['s'] = divmod(rem, 60)
return pattern.format(**d)
Examples:
>>> td = timedelta(seconds=123456789)
>>> period(td, "{d} days {h}:{m}:{s}")
'1428 days 21:33:9'
>>> period(td, "{h} hours, {m} minutes and {s} seconds, {d} days")
'21 hours, 33 minutes and 9 seconds, 1428 days'
Following Joe's example value above, I'd use the modulus arithmetic operator, thusly:
td = datetime.timedelta(hours=10.56)
td_str = "%d:%d" % (td.seconds/3600, td.seconds%3600/60)
Note that integer division in Python rounds down by default; if you want to be more explicit, use math.floor() or math.ceil() as appropriate.
One liner. Since timedeltas do not offer datetime's strftime, bring the timedelta back to a datetime, and use stftime.
This can not only achieve the OP's requested format Hours:Minutes, now you can leverage the full formatting power of datetime's strftime, should your requirements change to another representation.
import datetime
td = datetime.timedelta(hours=2, minutes=10, seconds=5)
print(td)
print(datetime.datetime.strftime(datetime.datetime.strptime(str(td), "%H:%M:%S"), "%H:%M"))
Output:
2:10:05
02:10
This also solves the annoyance that timedeltas are formatted into strings as H:MM:SS rather than HH:MM:SS, which lead me to this problem, and the solution I've shared.
import datetime
hours = datetime.timedelta(hours=16, minutes=30)
print((datetime.datetime(1,1,1) + hours).strftime('%H:%M'))
def seconds_to_time_left_string(total_seconds):
s = int(total_seconds)
years = s // 31104000
if years > 1:
return '%d years' % years
s = s - (years * 31104000)
months = s // 2592000
if years == 1:
r = 'one year'
if months > 0:
r += ' and %d months' % months
return r
if months > 1:
return '%d months' % months
s = s - (months * 2592000)
days = s // 86400
if months == 1:
r = 'one month'
if days > 0:
r += ' and %d days' % days
return r
if days > 1:
return '%d days' % days
s = s - (days * 86400)
hours = s // 3600
if days == 1:
r = 'one day'
if hours > 0:
r += ' and %d hours' % hours
return r
s = s - (hours * 3600)
minutes = s // 60
seconds = s - (minutes * 60)
if hours >= 6:
return '%d hours' % hours
if hours >= 1:
r = '%d hours' % hours
if hours == 1:
r = 'one hour'
if minutes > 0:
r += ' and %d minutes' % minutes
return r
if minutes == 1:
r = 'one minute'
if seconds > 0:
r += ' and %d seconds' % seconds
return r
if minutes == 0:
return '%d seconds' % seconds
if seconds == 0:
return '%d minutes' % minutes
return '%d minutes and %d seconds' % (minutes, seconds)
for i in range(10):
print pow(8, i), seconds_to_time_left_string(pow(8, i))
Output:
1 1 seconds
8 8 seconds
64 one minute and 4 seconds
512 8 minutes and 32 seconds
4096 one hour and 8 minutes
32768 9 hours
262144 3 days
2097152 24 days
16777216 6 months
134217728 4 years
I had a similar problem with the output of overtime calculation at work. The value should always show up in HH:MM, even when it is greater than one day and the value can get negative. I combined some of the shown solutions and maybe someone else find this solution useful. I realized that if the timedelta value is negative most of the shown solutions with the divmod method doesn't work out of the box:
def td2HHMMstr(td):
'''Convert timedelta objects to a HH:MM string with (+/-) sign'''
if td < datetime.timedelta(seconds=0):
sign='-'
td = -td
else:
sign = ''
tdhours, rem = divmod(td.total_seconds(), 3600)
tdminutes, rem = divmod(rem, 60)
tdstr = '{}{:}:{:02d}'.format(sign, int(tdhours), int(tdminutes))
return tdstr
timedelta to HH:MM string:
td2HHMMstr(datetime.timedelta(hours=1, minutes=45))
'1:54'
td2HHMMstr(datetime.timedelta(days=2, hours=3, minutes=2))
'51:02'
td2HHMMstr(datetime.timedelta(hours=-3, minutes=-2))
'-3:02'
td2HHMMstr(datetime.timedelta(days=-35, hours=-3, minutes=-2))
'-843:02'
from django.utils.translation import ngettext
def localize_timedelta(delta):
ret = []
num_years = int(delta.days / 365)
if num_years > 0:
delta -= timedelta(days=num_years * 365)
ret.append(ngettext('%d year', '%d years', num_years) % num_years)
if delta.days > 0:
ret.append(ngettext('%d day', '%d days', delta.days) % delta.days)
num_hours = int(delta.seconds / 3600)
if num_hours > 0:
delta -= timedelta(hours=num_hours)
ret.append(ngettext('%d hour', '%d hours', num_hours) % num_hours)
num_minutes = int(delta.seconds / 60)
if num_minutes > 0:
ret.append(ngettext('%d minute', '%d minutes', num_minutes) % num_minutes)
return ' '.join(ret)
This will produce:
>>> from datetime import timedelta
>>> localize_timedelta(timedelta(days=3660, minutes=500))
'10 years 10 days 8 hours 20 minutes'
A straight forward template filter for this problem. The built-in function int() never rounds up. F-Strings (i.e. f'') require python 3.6.
#app_template_filter()
def diffTime(end, start):
diff = (end - start).total_seconds()
d = int(diff / 86400)
h = int((diff - (d * 86400)) / 3600)
m = int((diff - (d * 86400 + h * 3600)) / 60)
s = int((diff - (d * 86400 + h * 3600 + m *60)))
if d > 0:
fdiff = f'{d}d {h}h {m}m {s}s'
elif h > 0:
fdiff = f'{h}h {m}m {s}s'
elif m > 0:
fdiff = f'{m}m {s}s'
else:
fdiff = f'{s}s'
return fdiff
If you happen to have IPython in your packages (you should), it has (up to now, anyway) a very nice formatter for durations (in float seconds). That is used in various places, for example by the %%time cell magic. I like the format it produces for short durations:
>>> from IPython.core.magics.execution import _format_time
>>>
>>> for v in range(-9, 10, 2):
... dt = 1.25 * 10**v
... print(_format_time(dt))
1.25 ns
125 ns
12.5 µs
1.25 ms
125 ms
12.5 s
20min 50s
1d 10h 43min 20s
144d 16h 13min 20s
14467d 14h 13min 20s
I continued from MarredCheese's answer and added year, month, millicesond and microsecond
all numbers are formatted to integer except for second, thus the fraction of a second can be customized.
#kfmfe04 asked for fraction of a second so I posted this solution
In the main there are some examples.
from string import Formatter
from datetime import timedelta
def strfdelta(tdelta, fmt='{D:02}d {H:02}h {M:02}m {S:02.0f}s', inputtype='timedelta'):
"""Convert a datetime.timedelta object or a regular number to a custom-
formatted string, just like the stftime() method does for datetime.datetime
objects.
The fmt argument allows custom formatting to be specified. Fields can
include seconds, minutes, hours, days, and weeks. Each field is optional.
Some examples:
'{D:02}d {H:02}h {M:02}m {S:02.0f}s' --> '05d 08h 04m 02s' (default)
'{W}w {D}d {H}:{M:02}:{S:02.0f}' --> '4w 5d 8:04:02'
'{D:2}d {H:2}:{M:02}:{S:02.0f}' --> ' 5d 8:04:02'
'{H}h {S:.0f}s' --> '72h 800s'
The inputtype argument allows tdelta to be a regular number instead of the
default, which is a datetime.timedelta object. Valid inputtype strings:
's', 'seconds',
'm', 'minutes',
'h', 'hours',
'd', 'days',
'w', 'weeks'
"""
# Convert tdelta to integer seconds.
if inputtype == 'timedelta':
remainder = tdelta.total_seconds()
elif inputtype in ['s', 'seconds']:
remainder = float(tdelta)
elif inputtype in ['m', 'minutes']:
remainder = float(tdelta)*60
elif inputtype in ['h', 'hours']:
remainder = float(tdelta)*3600
elif inputtype in ['d', 'days']:
remainder = float(tdelta)*86400
elif inputtype in ['w', 'weeks']:
remainder = float(tdelta)*604800
f = Formatter()
desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)]
possible_fields = ('Y','m','W', 'D', 'H', 'M', 'S', 'mS', 'µS')
constants = {'Y':86400*365.24,'m': 86400*30.44 ,'W': 604800, 'D': 86400, 'H': 3600, 'M': 60, 'S': 1, 'mS': 1/pow(10,3) , 'µS':1/pow(10,6)}
values = {}
for field in possible_fields:
if field in desired_fields and field in constants:
Quotient, remainder = divmod(remainder, constants[field])
values[field] = int(Quotient) if field != 'S' else Quotient + remainder
return f.format(fmt, **values)
if __name__ == "__main__":
td = timedelta(days=717, hours=3, minutes=5, seconds=8, microseconds=3549)
print(strfdelta(td,'{Y} years {m} months {W} weeks {D} days {H:02}:{M:02}:{S:02}'))
print(strfdelta(td,'{m} months {W} weeks {D} days {H:02}:{M:02}:{S:02.4f}'))
td = timedelta( seconds=8, microseconds=8549)
print(strfdelta(td,'{S} seconds {mS} milliseconds {µS} microseconds'))
print(strfdelta(td,'{S:.0f} seconds {mS} milliseconds {µS} microseconds'))
print(strfdelta(pow(10,7),inputtype='s'))
Output:
1 years 11 months 2 weeks 3 days 01:09:56.00354900211096
23 months 2 weeks 3 days 00:12:20.0035
8.008549 seconds 8 milliseconds 549 microseconds
8 seconds 8 milliseconds 549 microseconds
115d 17h 46m 40s
Here's a function to stringify timedelta.total_seconds(). It works in python 2 and 3.
def strf_interval(seconds):
days, remainder = divmod(seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
return '{} {} {} {}'.format(
"" if int(days) == 0 else str(int(days)) + ' days',
"" if int(hours) == 0 else str(int(hours)) + ' hours',
"" if int(minutes) == 0 else str(int(minutes)) + ' mins',
"" if int(seconds) == 0 else str(int(seconds)) + ' secs'
)
Example output:
>>> print(strf_interval(1))
1 secs
>>> print(strf_interval(100))
1 mins 40 secs
>>> print(strf_interval(1000))
16 mins 40 secs
>>> print(strf_interval(10000))
2 hours 46 mins 40 secs
>>> print(strf_interval(100000))
1 days 3 hours 46 mins 40 secs
timedelta to string, use for print running time info.
def strfdelta_round(tdelta, round_period='second'):
"""timedelta to string, use for measure running time
attend period from days downto smaller period, round to minimum period
omit zero value period
"""
period_names = ('day', 'hour', 'minute', 'second', 'millisecond')
if round_period not in period_names:
raise Exception(f'round_period "{round_period}" invalid, should be one of {",".join(period_names)}')
period_seconds = (86400, 3600, 60, 1, 1/pow(10,3))
period_desc = ('days', 'hours', 'mins', 'secs', 'msecs')
round_i = period_names.index(round_period)
s = ''
remainder = tdelta.total_seconds()
for i in range(len(period_names)):
q, remainder = divmod(remainder, period_seconds[i])
if int(q)>0:
if not len(s)==0:
s += ' '
s += f'{q:.0f} {period_desc[i]}'
if i==round_i:
break
if i==round_i+1:
s += f'{remainder} {period_desc[round_i]}'
break
return s
e.g. auto omit zero leading period:
>>> td = timedelta(days=0, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'second')
'2 hours 5 mins 8 secs'
or omit middle zero period:
>>> td = timedelta(days=2, hours=0, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'millisecond')
'2 days 5 mins 8 secs 3 msecs'
or round to minutes, omit below minutes:
>>> td = timedelta(days=1, hours=2, minutes=5, seconds=8, microseconds=3549)
>>> strfdelta_round(td, 'minute')
'1 days 2 hours 5 mins'
Please check this function - it converts timedelta object into string 'HH:MM:SS'
def format_timedelta(td):
hours, remainder = divmod(td.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
hours, minutes, seconds = int(hours), int(minutes), int(seconds)
if hours < 10:
hours = '0%s' % int(hours)
if minutes < 10:
minutes = '0%s' % minutes
if seconds < 10:
seconds = '0%s' % seconds
return '%s:%s:%s' % (hours, minutes, seconds)
If you already have a timedelta obj then just convert that obj into string. Remove the last 3 characters of the string and print. This will truncate the seconds part and print the rest of it in the format Hours:Minutes.
t = str(timedeltaobj)
print t[:-3]
I wanted to do this so wrote a simple function. It works great for me and is quite versatile (supports years to microseconds, and any granularity level, e.g. you can pick between '2 days, 4 hours, 48 minutes' and '2 days, 4 hours' and '2 days, 4.8 hours', etc.
def pretty_print_timedelta(t, max_components=None, max_decimal_places=2):
'''
Print a pretty string for a timedelta.
For example datetime.timedelta(days=2, seconds=17280) will be printed as '2 days, 4 hours, 48 minutes'. Setting max_components to e.g. 1 will change this to '2.2 days', where the
number of decimal points can also be set.
'''
time_scales = [timedelta(days=365), timedelta(days=1), timedelta(hours=1), timedelta(minutes=1), timedelta(seconds=1), timedelta(microseconds=1000), timedelta(microseconds=1)]
time_scale_names_dict = {timedelta(days=365): 'year',
timedelta(days=1): 'day',
timedelta(hours=1): 'hour',
timedelta(minutes=1): 'minute',
timedelta(seconds=1): 'second',
timedelta(microseconds=1000): 'millisecond',
timedelta(microseconds=1): 'microsecond'}
count = 0
txt = ''
first = True
for scale in time_scales:
if t >= scale:
count += 1
if count == max_components:
n = t / scale
else:
n = int(t / scale)
t -= n*scale
n_txt = str(round(n, max_decimal_places))
if n_txt[-2:]=='.0': n_txt = n_txt[:-2]
txt += '{}{} {}{}'.format('' if first else ', ', n_txt, time_scale_names_dict[scale], 's' if n>1 else '', )
if first:
first = False
if len(txt) == 0:
txt = 'none'
return txt
I had the same problem and I am using pandas Timedeltas, didn't want to bring in additional dependencies (another answer mentions humanfriendly) so I wrote this small function to print out only the relevant information:
def format_timedelta(td: pd.Timedelta) -> str:
if pd.isnull(td):
return str(td)
else:
c = td.components._asdict()
return ", ".join(f"{n} {unit}" for unit, n in c.items() if n)
For example, pd.Timedelta(hours=3, seconds=12) would print as 3 hours, 12 seconds.
I suggest the following method so that we can utilize the standard formatting function, pandas.Timestamp.strftime!
from pandas import Timestamp, Timedelta
(Timedelta("2 hours 30 min") + Timestamp("00:00:00")).strftime("%H:%M")

Categories