The hour that does not exist, and the hour that happens twice
A clock change does not move time. It deletes an hour from the local calendar, or plays one twice — and code that assumes every local time is real, and unique, breaks on both.
Two different failures, not one
People think of a clock change as a single event. For anything that has to compute with dates it is two, and they fail in opposite directions.
Spring forward: a gap
When clocks jump forward, a stretch of local time is simply skipped. If the change is at 02:00 and the clock goes straight to 03:00, then 02:30 did not happen that day. It is not ambiguous, not rare, not a rounding artefact — it is a local time that has no instant behind it.
Ask a system to schedule something for 02:30 on that date and there is no correct answer, only a choice of wrong ones: refuse it, push it to 03:30, pull it back to 01:30, or silently produce whatever the underlying library happens to do. Most libraries do something. Few announce it.
Fall back: a repeat
The reverse is worse, because nothing errors. When clocks go back, a stretch of local time happens twice. 01:30 comes round, an hour passes, and it is 01:30 again — two different instants, an hour apart, wearing the same label.
A local timestamp inside that window is genuinely ambiguous. Records written during it can sort into the wrong order. A duration measured across it can come out an hour short. And a job set to run at that local time may run twice, or once, depending on the scheduler — usually without anybody noticing until the second invoice goes out.
The consequence that catches everyone: the day is not 24 hours
On those two days a local day is 23 or 25 hours long. That sounds like trivia until you notice how much software adds 24 hours to get to tomorrow.
A calendar grid built by repeatedly adding twenty-four hours drifts by one row the moment it crosses a transition — and it drifts at exactly the moment a person is trying to work out whether a meeting is at a sane hour for someone else. This is why our meeting planner steps through instants and asks the zone what the local reading is at each one, rather than incrementing a clock face. The 23- and 25-hour days then come out correct because nothing ever assumed they would not.
What actually protects you
- Do arithmetic in instants, present in local time. Convert to a named zone at the edge, when you display. Never in the middle of a calculation.
- Treat a local time as a question, not a value. “02:30 on that date in that zone” may have zero answers or two. Code that assumes exactly one is code that works 363 days a year.
- Test the boundaries deliberately. Randomly sampled dates almost never land in the gap or the repeat — the windows are one hour wide, twice a year. If your test data is random, the region where the bug lives is the region your tests do not reach. Ours are pinned explicitly, which is described on how we test.
- Never store an offset for a future event. Store the zone. The reasoning is in a time zone is not an offset.
Why no dates appear on this page
You will notice this page names no country and no transition date. That is deliberate. Transition rules are set by legislation and change with little notice, and a date baked into a static page is a claim that nobody goes back to re-read. The time zone changes page carries the changes we have verified, with their sources; the structure described here is true everywhere and cannot go stale.