Dates with a timezone
Calculate elapsed hours between timezone-aware timestamps.
A timestamp needs context
datetime.fromisoformat() parses ISO-formatted text into a datetime. A timestamp with Z or a numeric offset identifies an instant; one without an offset is naive. Mixing naive and aware values can fail or make a report ambiguous.
Use datetime.now(timezone.utc) when you need the current instant in your own tool. Tests should supply a fixed reference time so yesterday’s correct solution still passes tomorrow. This course therefore passes reference timestamps explicitly.
Subtract instants, not clock labels
Subtracting aware datetimes accounts for their UTC offsets and returns a timedelta. Use total_seconds() to include the entire duration. Its seconds attribute is only the seconds portion after whole days are removed, so it is wrong for multi-day age calculations.
Divide by 3600 to get hours. A future timestamp produces a negative age; that can be useful evidence of clock skew and should not be silently turned into zero. Reject naive inputs clearly instead of guessing their timezone. Your browser’s local timezone should not change the result.
from datetime import datetime
start = datetime.fromisoformat("2026-01-01T08:00:00+10:00")
end = datetime.fromisoformat("2026-01-01T00:00:00Z")
print((end - start).total_seconds() / 3600)
Put it into practice.
Define age_hours(timestamp, reference). Parse both ISO timestamps, require timezone information, and return (reference - timestamp) in hours. Accept different UTC offsets and negative ages. Raise ValueError for naive timestamps.
See an explained solution
from datetime import datetime
def age_hours(timestamp, reference):
start = datetime.fromisoformat(timestamp)
end = datetime.fromisoformat(reference)
if start.utcoffset() is None or end.utcoffset() is None:
raise ValueError("Both timestamps need a timezone")
return (end - start).total_seconds() / 3600
Timezone-aware subtraction compares instants correctly. A fixed reference makes tests deterministic, and total_seconds preserves both long durations and negative results.