Pretty print uptime given seconds and omit unnecessary strings

Given an integer number of seconds, return a string which represents in human readable format the number of days/hours/minutes/seconds that are equivalent.

from datetime import datetime, timedelta

def GetTime(sec):
d = datetime(1,1,1) + timedelta(seconds=sec)
days = (d.day-1,'d',' ') if (d.day-1 > 0) else ('','','')
hours = (d.hour, 'h', ' ') if (d.hour > 0) else ('', '', '')
mins = (d.minute, 'm', ' ') if (d.minute > 0) else ('', '', '')
secs = (d.second, 's', ' ') if (d.second > 0) else ('', '', '')
time_format = days + hours + mins + secs
format_str = '{}'*len(time_format)

return format_str.format(*time_format)


I think there might be a better way to do the formatting to omit values that are zero instead of combining tuples and exploding them in the format string.

I feel like the datetime module isn't really doing much to help you. By using it, you avoid performing arithmetic and hard-coding constants 86400, 3600, and 60. However, in exchange, you end up hard-coding the accessors .day, .hour, .minute, and .second, in such a way that you have to write similar code four times, with no easy way to generalize them. Attempts at generalization are further complicated by the fact that you need d.day-1, due to the way that you have abused datetime addition as a trick to convert the timedelta object into a datetime object.

Your output includes a trailing space, which I consider to be an annoyance. One way to avoid that would be to use ' '.join(…). On the other hand, if sec is 0, then the function would return an empty string, which is also unintuitive. I would prefer 0s as output in that special case.

In my opinion, you would be no worse off doing all of the arithmetic and formatting yourself, without the use of the datetime module.

def format_seconds(sec):
def repeatedly(f, xs, n):
for x in xs:
m, n = f(n, x)
yield m
return ' '.join(
'{}{}'.format(n, unit)
for n, unit in zip(
repeatedly(divmod, [86400, 3600, 60, 1], sec),
'dhms'
)
if n
) or '0s'