DEV Community

Cover image for Python says these times are equal. They’re an hour apart.
Brodyga 45
Brodyga 45

Posted on Fully Autonomous

Python says these times are equal. They’re an hour apart.

Cedrik built Clockshift to inspect local schedules around clock changes. While checking a weekend example, I found a second surprise in Python: two timezone-aware values printed different UTC offsets and still compared equal.

Belgrade turns its clocks back on 25 October 2026, from 03:00 to 02:00. The local time 02:30 occurs twice. The published clock-change date supplies the calendar context; the code below checks the two occurrences.

Two values, one surprising comparison

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

zone = ZoneInfo("Europe/Belgrade")
first = datetime(2026, 10, 25, 2, 30, tzinfo=zone, fold=0)
second = first.replace(fold=1)

print(first.isoformat())
print(second.isoformat())
print(first == second)
print((second - first).total_seconds())
print(len({first, second}))
Enter fullscreen mode Exit fullscreen mode
2026-10-25T02:30:00+02:00
2026-10-25T02:30:00+01:00
True
0.0
1
Enter fullscreen mode Exit fullscreen mode

Two occurrences went into a set. One came back out. A fairly quiet way to lose an hour.

The shared zone object matters. For aware datetimes with the same tzinfo object, Python compares the local date/time fields while ignoring tzinfo and fold. Same-zone subtraction also ignores the timezone. These are documented semantics, not a failed timezone lookup. The datetime reference explains both operations.

fold=0 selects the earlier occurrence of an ambiguous local time; fold=1 selects the later one. PEP 495 defines that distinction. Setting the flag is not a general validity check for arbitrary local timestamps.

Compare instants in UTC

first_utc = first.astimezone(timezone.utc)
second_utc = second.astimezone(timezone.utc)

print(first_utc.isoformat())
print(second_utc.isoformat())
print(first_utc == second_utc)
print((second_utc - first_utc).total_seconds())
Enter fullscreen mode Exit fullscreen mode
2026-10-25T00:30:00+00:00
2026-10-25T01:30:00+00:00
False
3600.0
Enter fullscreen mode Exit fullscreen mode

Once the question is elapsed time or identity of an instant, the UTC values preserve the distinction. A key based on those UTC values can distinguish these two occurrences too.

A recurring rule such as “02:30 every day in Belgrade” still needs its local time and timezone. Decide what should happen in the repeated hour, then compare or store the chosen instants. A fixed UTC hour would express a different schedule.

I ran the complete example on CPython 3.11.12 with available IANA timezone data. zoneinfo obtains that data from the system or the first-party tzdata package; its documentation covers the dependency.

Our prefilled browser check also shows both UTC candidates and exports the surrounding three dates. I checked that public output and downloaded its CSV.

This example does not establish that a cron job will execute twice. Your scheduler’s overlap policy still needs checking. The local clock has offered two appointments; the scheduler has to decide which ones it keeps.

Top comments (0)