I’ve got a timedelta. I want the days, hours and minutes from that – either as a tuple or a dictionary… I’m not fussed.
I must have done this a dozen times in a dozen languages over the years but Python usually has a simple answer to everything so I thought I’d ask here before busting out some nauseatingly simple (yet verbose) mathematics.
Mr Fooz raises a good point.
I’m dealing with “listings” (a bit like ebay listings) where each one has a duration. I’m trying to find the time left by doing when_added + duration - now
Am I right in saying that wouldn’t account for DST? If not, what’s the simplest way to add/subtract an hour?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
If you have a datetime.timedelta value td, td.days already gives you the “days” you want. timedelta values keep fraction-of-day as seconds (not directly hours or minutes) so you’ll indeed have to perform “nauseatingly simple mathematics”, e.g.:
def days_hours_minutes(td):
return td.days, td.seconds//3600, (td.seconds//60)%60
Method 2
This is a bit more compact, you get the hours, minutes and seconds in two lines.
days = td.days hours, remainder = divmod(td.seconds, 3600) minutes, seconds = divmod(remainder, 60) # If you want to take into account fractions of a second seconds += td.microseconds / 1e6
Method 3
days, hours, minutes = td.days, td.seconds // 3600, td.seconds // 60 % 60
As for DST, I think the best thing is to convert both datetime objects to seconds. This way the system calculates DST for you.
>>> m13 = datetime(2010, 3, 13, 8, 0, 0) # 2010 March 13 8:00 AM >>> m14 = datetime(2010, 3, 14, 8, 0, 0) # DST starts on this day, in my time zone >>> mktime(m14.timetuple()) - mktime(m13.timetuple()) # difference in seconds 82800.0 >>> _/3600 # convert to hours 23.0
Method 4
I don’t understand
days, hours, minutes = td.days, td.seconds // 3600, td.seconds // 60 % 60
how about this
days, hours, minutes = td.days, td.seconds // 3600, td.seconds % 3600 / 60.0
You get minutes and seconds of a minute as a float.
Method 5
For all coming along and searching for an implementation:
The above posts are related to datetime.timedelta, which is sadly not having properties for hours and seconds. So far it was not mentioned, that there is a package, which is having these. You can find it here:
- Check the source: https://github.com/andrewp-as-is/timedelta.py
- Available via pip: https://pypi.org/project/timedelta/
Example – Calculation:
>>> import timedelta >>> td = timedelta.Timedelta(days=2, hours=2) # init from datetime.timedelta >>> td = timedelta.Timedelta(datetime1 - datetime2)
Example – Properties:
>>> td = timedelta.Timedelta(days=2, hours=2) >>> td.total.seconds 180000 >>> td.total.minutes 3000 >>> td.total.hours 50 >>> td.total.days 2
I hope this could help someone…
Method 6
I used the following:
delta = timedelta()
totalMinute, second = divmod(delta.seconds, 60)
hour, minute = divmod(totalMinute, 60)
print(f"{hour}h{minute:02}m{second:02}s")
Method 7
I found the easiest way is using str(timedelta). It will return a sting formatted like 3 days, 21:06:40.001000, and you can parse hours and minutes using simple string operations or regular expression.
Method 8
Here is a little function I put together to do this right down to microseconds:
def tdToDict(td:datetime.timedelta) -> dict:
def __t(t, n):
if t < n: return (t, 0)
v = t//n
return (t - (v * n), v)
(s, h) = __t(td.seconds, 3600)
(s, m) = __t(s, 60)
(micS, milS) = __t(td.microseconds, 1000)
return {
'days': td.days
,'hours': h
,'minutes': m
,'seconds': s
,'milliseconds': milS
,'microseconds': micS
}
Here is a version that returns a tuple:
# usage: (_d, _h, _m, _s, _mils, _mics) = tdTuple(td)
def tdTuple(td:datetime.timedelta) -> tuple:
def _t(t, n):
if t < n: return (t, 0)
v = t//n
return (t - (v * n), v)
(s, h) = _t(td.seconds, 3600)
(s, m) = _t(s, 60)
(mics, mils) = _t(td.microseconds, 1000)
return (td.days, h, m, s, mics, mils)
Method 9
While pandas.Timedelta does not provide these attributes directly, it indeed provide a method called total_seconds, based on which days, hours, and minutes can be easily derived:
import pandas as pd
td = pd.Timedelta("2 days 12:30:00")
minutes = td.total_seconds()/60
hours = minutes/60
days = hours/ 24
print(minutes, hours, days)
Method 10
This is another possible approach, though a bit wordier than those already mentioned. It maybe isn’t the best approach for this scenario but it is handy to be able to obtain your time duration in a specific unit that isn’t stored within the object (weeks, hours, minutes, milliseconds) and without having to remember or calculate conversion factors.
from datetime import timedelta
one_hour = timedelta(hours=1)
one_minute = timedelta(minutes=1)
print(one_hour/one_minute) # Yields 60.0
I’ve got a timedelta. I want the days, hours and minutes from that – either as a tuple or a dictionary… I’m not fussed.
in_time_delta = timedelta(days=2, hours=18, minutes=30)
td_d = timedelta(days=1)
td_h = timedelta(hours=1)
td_m = timedelta(minutes=1)
dmh_list = [in_time_delta.days,
(in_time_delta%td_d)//td_h,
(in_time_delta%td_h)//td_m]
Which should assign [2, 18, 30] to dmh_list
Method 11
If using pandas (at least version >1.0), the Timedelta class has a components attribute that returns a named tuple with all the fields nicely laid out.
e.g.
import pandas as pd
delta = pd.Timestamp("today") - pd.Timestamp("2022-03-01")
print(delta.components)
Method 12
timedeltas have a days and seconds attribute .. you can convert them yourself with ease.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0