Timezones are the bug you ship on a Sunday

Checked 22 Sep 2026 · By Luke Czak

ArticleUnderstanding AIFree to read

A timestamp with no explicit timezone is not neutral. It silently assumes every machine that reads it shares the same clock, and that assumption breaks exactly when a scheduled job or a seasonal clock shift proves it wrong.

A scheduled task in one of my pipelines fired an hour later than it should have, on a weekend, and it took me longer than it should have to work out why, because the code had never once mentioned a timezone anywhere I could see it. It did not need to mention one for the bug to exist. The absence of an explicit timezone is itself a choice, made silently on someone’s behalf, and the choice it defaults to is whatever the machine running the code happens to be set to at that particular moment.

A timestamp with no timezone attached to it is not a neutral, universal fact the way it feels like it should be. It is a number that only means something once you know where and when it was interpreted, and code that stores or compares those numbers without ever recording that context is quietly betting that every machine that ever reads the value agrees on what it means. That bet holds for a surprisingly long time, right up until it does not — a job moves to a server in a different region, a laptop’s clock observes a seasonal shift the server’s clock does not, or two pieces of code that generated their timestamps an ocean apart get compared as if they came from the same clock.

These bugs cluster around exactly the moments nobody is looking, which is not a coincidence. A seasonal clock change lands on a weekend specifically because that is when the disruption of shifting everyone’s clocks costs the least, which means the shift itself, and the code that silently assumed it would never happen, both land on the one stretch of the week that testing during business hours never covers. A job scheduled to run at a fixed local time drifts relative to everything scheduled in a fixed absolute time the moment that shift happens, and the drift is exactly one hour: small enough to look like a fluke, large enough to matter, and it happens on the day least likely to have anyone watching a dashboard when it does.

The fix I have settled on is treating every timestamp as an unanswered question until the code that produced it says otherwise explicitly. Store and compare time in an unambiguous, timezone-aware form throughout the system, and convert to a local, human-facing time only at the last possible moment, for display, never for arithmetic. Any comparison, duration, or scheduling decision made on a value that has not been pinned to an explicit point in absolute time is quietly assuming two clocks agree, and the entire point of this class of bug is that they eventually do not. It costs almost nothing to be explicit about this from the start of a project. It costs a genuinely irritating amount of time to retrofit once a dozen places in a codebase have each made their own silent assumption about whose clock is the true one.

None of this is exotic once you have been bitten by it, which is exactly why it keeps catching people who have not been yet: the failure mode is boring, well understood, and still shows up in new code every year, because writing a timestamp without thinking about its timezone is the path of least resistance, and the bug it produces sits dormant for months before the one day it actually matters. I now assume, by default, that any timestamp I have not deliberately made explicit is wrong in a way I have not discovered yet. It is a cheap assumption to hold and an expensive one to have skipped, and it always seems to be a weekend by the time it finally shows itself.

Comments (0)

Sign in to comment.