Unix Time, Time Zones, and Expiry Bugs
Time bugs are rarely about time arithmetic. They come from a unit mismatch, an implicit time zone, or a clock that disagrees with another machine. Each has a recognisable signature once you know what to look for.
Seconds or milliseconds, decided by digit count
Unix time counts seconds since 1970-01-01T00:00:00Z, but a large part of the ecosystem counts milliseconds instead. JWT claims, Unix tooling, and most SQL epoch functions use seconds; JavaScript, the JVM, and many log pipelines use milliseconds. Mixing the two is the single most common time defect in web systems.
The diagnosis takes a second: a present-day timestamp in seconds has ten digits, in milliseconds thirteen. A token whose expiry appears to be tens of thousands of years away was written in milliseconds and read as seconds. A token that expires the instant it is issued is the same mistake in reverse.
Store the instant, render the zone
A Unix timestamp has no time zone, which is its main virtue. Problems begin when a date is stored or compared in local time. Daylight-saving transitions then make one hour ambiguous and another nonexistent, which is why a scheduled job appears to run twice or not at all on two days each year.
The durable rule is to store and compute in UTC and convert only at the point of display. When you share a time with another person, quote the ISO 8601 form with its offset, so 2025-06-15T15:06:40Z leaves nothing to interpret.
- Confirm the unit by digit count before doing any arithmetic.
- Convert to ISO 8601 in UTC when comparing values from two systems.
- Check clock drift between the issuer and the verifier when a token is rejected at the boundary.
- Render local time only in the user interface, and always show the zone.
Expiry, skew, and the boundaries that still bite
Token validation compares exp, nbf, and iat against the verifier clock. If two servers differ by a few seconds and no leeway is configured, a freshly issued token can be rejected as not yet valid. A small allowance, usually thirty to sixty seconds, plus synchronised clocks, removes an entire class of intermittent authentication failures.
Two boundaries remain worth testing deliberately. A signed 32-bit time_t overflows on 19 January 2038, which still affects embedded devices and old database columns. And Unix time deliberately ignores leap seconds, treating every day as exactly 86,400 seconds, so it should never be treated as an exact measure of elapsed physical time across decades.