How do I work with durations in pandas?
Short answer
Subtracting datetimes gives a Timedelta, which you convert to a number with total_seconds or dt.days. Use total_seconds and divide, because dt.days truncates and dt.hours only gives the hour component.
The short version
Subtracting two datetimes gives a Timedelta. Convert it to a number with dt.total_seconds() and divide to your chosen unit. Do not reach for dt.days and dt.components.hours expecting a total, because they give parts of the duration, not the whole of it.
The component trap
import pandas as pd
td = pd.Series(pd.to_timedelta(["1 days 02:00:00"]))
td.dt.days.tolist() # [1] , just the days part
(td.dt.total_seconds() / 3600).tolist() # [26.0] , the TOTAL in hours
The duration is 26 hours. dt.days reports 1, because it gives only the whole-days component, discarding the extra 2 hours. total_seconds() gives the entire duration, which you then divide into whatever unit you want.
This trips people up constantly. If you want "how many hours in total", you must use total_seconds() / 3600, not a component accessor.
Converting to common units
td.dt.total_seconds() # seconds
td.dt.total_seconds() / 60 # minutes
td.dt.total_seconds() / 3600 # hours
td.dt.total_seconds() / 86400 # days, including the fractional part
Note the last one differs from dt.days, which truncates. A duration of 1.5 days gives 1.5 here and 1 from dt.days.
Creating a duration
pd.Timedelta(hours=2, minutes=30)
pd.Timedelta("90 minutes")
Use these for thresholds and for date arithmetic, rather than computing seconds by hand.
df[df["gap"] > pd.Timedelta(hours=24)] # gaps of more than a day
df["deadline"] = df["created"] + pd.Timedelta(days=7)
Timedeltas aggregate
A Timedelta column supports mean, sum, min and max directly, which is convenient for summarising durations.
df["duration"].mean() # a Timedelta, printed readably
Keep it as a Timedelta for aggregation and readability, and convert to a number only when you need to plot it, compare it against a numeric threshold, or feed it into a model.
Negative durations
Subtracting datetimes in the wrong order gives a negative Timedelta, which is valid and will quietly flow through a mean, dragging it down. If negative durations are impossible in your data, check for them, because they usually mean two timestamps are the wrong way round, which is a real data problem worth finding.
(df["end"] < df["start"]).sum() # how many rows are inverted
The daylight saving caveat
If the two timestamps are in a local timezone and span a clock change, their difference in wall-clock terms is not the true elapsed time. Compute durations in UTC to get the real answer, which is the safe discipline for any duration that matters.