6

I have hours in this format,

72.345, 72.629, 71.327, ...

as a result of performing a calculation in Python. It seems that the simplest way to convert these into HH:MM:SS format is using the datetime module like this:

time = str(datetime.timedelta(seconds = 72.345*3600))

However, that returns a values with days, which I don't want:

'3 days, 0:20:42'

This is the best way my brain came up with the final values I want:

str(int(math.floor(time))) + ':' + str(int((time%(math.floor(time)))*60)) + ':' + str(int(((time%(math.floor(time)))*60) % math.floor(((time%(math.floor(time)))*60))*60))

Which is ridiculously long and probably unnecessary. But it does give me the answer I want:

'72:20:41'

Are there better methods?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
traggatmot
  • 1,423
  • 5
  • 26
  • 51

5 Answers5

13

You do not have to use datetime. You can easily compute hours, minutes and seconds from your decimal time.

You should also notice that you can use string formatting which is really easier to use than string concatenation.

time = 72.345

hours = int(time)
minutes = (time*60) % 60
seconds = (time*3600) % 60

print("%d:%02d.%02d" % (hours, minutes, seconds))
>> 72:20:42
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Delgan
  • 18,571
  • 11
  • 90
  • 141
4

If you want it to be a little easier to look at, you can always put in:

Time = 72.345

Hours = Time
Minutes = 60 * (Hours % 1)
Seconds = 60 * (Minutes % 1)

print("%d:%02d:%02d" % (Hours, Minutes, Seconds))

Putting %d in the string will cut off any decimals for you.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ThatGuyRussell
  • 1,361
  • 9
  • 18
3

I am copying the best answer here to the question How do I convert seconds to hours, minutes and seconds?, because to my eyes, the following use of divmod and tuple assignment is so pleasing.

hours = 72.345
seconds = hours * 3600
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
print "%d:%02d:%02d" % (h, m, s)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rishi
  • 121
  • 4
  • In my eyes the best answer, if you have to deal with a repeating decimal number representing time, for instance `72.583... (72 hours and 35 minutes)`. Regarding these cases I would use an extra line `seconds = int(seconds+0.5)` and go on. – Erich Kuester Jul 05 '21 at 16:52
1

A functional approach:

First define a helper method, frac, which is somehow the same with math.modf:

>>> def frac(n):
...     i = int(n)
...     f = round((n - int(n)), 4)
...     return (i, f)
...
>>> frac(53.45)
(53, 0.45) # A tuple

Then a function to format the hours decimal:

>>> def frmt(hour): # You can rewrite it with 'while' if you wish
...     hours, _min = frac(hour)
...     minutes, _sec = frac(_min*60)
...     seconds, _msec = frac(_sec*60)
...     return "%s:%s:%s"%(hours, minutes, seconds)
...
>>> frmt(72.345)
'72:20:42'
>>> l = [72.345, 72.629, 71.327]
>>> map(frmt, l)
['72:20:42', '72:37:44', '71:19:37']
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
marmeladze
  • 6,468
  • 3
  • 24
  • 45
0

In this function you get a straight-forward answer with just 2 lines, which are very readable since they hide the math operations.

from dateutil.relativedelta import relativedelta
from typing import Tuple, Union

def decimal_hours_to_HMS(hours: float, as_tuple: bool = False) -> Union[str, Tuple]:
    """ 
    Converts a float number representing hours to a readable string of the form "HH:MM:SS"
    - as_tuple: set it to True if instead of a string, you want a tuple as (hours, minutes, seconds)
    
    Example:
    --------
    >> decimal_hours_to_HMS(hours=72.345)
    '72:20:42'
    >>> decimal_hours_to_HMS(hours=72.345, as_tuple=True)
    (72, 20, 42)
    """
    rd = relativedelta(hours=hours).normalized()
    str_repr = f"{rd.days * 24 + rd.hours}:{rd.minutes}:{rd.seconds}"
    return str_repr if not as_tuple else tuple(map(int, str_repr.split(":")))
  1. The first line is like a datetime.timedelta that accepts decimal values, which is normalized to translate the info to integer values.
  2. The second line extracts the total hours, the minutes and the seconds, in the string format you wanted.

As a bonus in the return, it lets you choose, with the parameter as_tuple, whether or not you want the output to be a tuple with the values of the hours, minutes and seconds. This functionality could come handy in many situations.

CharlieNeutron
  • 188
  • 1
  • 6