Django difference between aware datetimes across DST

I'm working on a Django application in which I need to calculate the difference between timestamps stored in the DB. This week I run into some problems related to DST.

In particular in the following code snippet:

tEndUtc = tEnd.astimezone(timezone.utc)
tStartUtc =  tStart.astimezone(timezone.utc)
total_timeUTC = tEndUtc- tStartUtc
total_time = tEnd - tStart

total_time (which uses the timezone aware timestamp stored in the DB) is shorter of 1 hour than the one with the total_timeUTC. I use have USE_TZ = true in the settings file.

Here's what I get:

tStart = datetime.datetime(2025, 10, 24, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Rome'))
tEnd = datetime.datetime(2025, 10, 31, 23, 59, 59, 999999, tzinfo=zoneinfo.ZoneInfo(key='Europe/Rome'))
tStartUtc  = datetime.datetime(2025, 10, 23, 22, 0, tzinfo=datetime.timezone.utc)
tEndUtc = datetime.datetime(2025, 10, 31, 22, 59, 59, 999999, tzinfo=datetime.timezone.utc)
total_timeUTC = datetime.timedelta(days=8, seconds=3599, microseconds=999999)
total_time = datetime.timedelta(days=7, seconds=86399, microseconds=999999)

What is the correct way to handle DST? And in particular how does someone correctly calculate time difference across DST?

The correct time delta is the one I get when using UTC. Having all the application built using timezone aware datetimes, I would like not change everything and convert to UTC timestamps.

Thanks in advance.

Interestingly this appears to be an "issue" with zoneinfo:

import pytz
from zoneinfo import ZoneInfo

z_rome = ZoneInfo('Europe/Rome')
p_rome = pytz.timezone('Europe/Rome')

datetime(2025, 10, 26, 4, tzinfo=z_rome) - datetime(2025, 10, 25, 4, tzinfo=z_rome)
# datetime.timedelta(days=1)
p_rome.localize(datetime(2025, 10, 26, 4)) - p_rome.localize(datetime(2025, 10, 25, 4))
# datetime.timedelta(days=1, seconds=3600)

According to pytz, 1 day and 1 hour elapsed between these two dates, which is the actual number of hours that have passed. But according to ZoneInfo, only 24 hours have elapsed, as it appears to do wall clock time arithmetic.

So, the difference is "correct", and converting to UTC does fix that behaviour and yield the expected duration:

datetime(2025, 10, 26, 4, tzinfo=z_rome).astimezone(timezone.utc) - datetime(2025, 10, 25, 4, tzinfo=z_rome).astimezone(timezone.utc)
# datetime.timedelta(days=1, seconds=3600)
Вернуться на верх