Unix Timestamps and Timezones: The Confusion That Eats Your Week
What a Unix timestamp is, why the same date string parses two different ways, the two hours DST breaks every year, and what Temporal changes.
Every developer understands time until the second Sunday in March.
What a Unix timestamp is
A count of seconds since 00:00:00 UTC on 1 January 1970, ignoring leap seconds. One number, no timezone attached, because it is always measured against UTC. At any instant every machine on earth should agree on it.
1761000000 is 20 October 2025 at 22:40 UTC. In Tokyo that reads 21 October, 07:40. In New York, still 20 October, 18:40. One moment, three ways of saying it, and only the number is the moment. Everything else is presentation.
Our Unix Timestamp Converter goes both ways in any zone.
Count the digits
- 10 digits,
1761000000, seconds. The classical form. - 13 digits,
1761000000000, milliseconds. WhatDate.now()returns. - 16 digits, microseconds. Common in databases and tracing systems.
Feed milliseconds to something expecting seconds and you land somewhere around the year 57,774, which is at least an obvious kind of wrong.
Zones are rules, offsets are numbers
An offset is a displacement: +05:30, -08:00. A zone is a rule that says which offset applies when.
+05:30 an offset, fixed forever
Asia/Kolkata a zone that is always +05:30
Europe/London a zone that is +00:00 in winter and +01:00 in summer
America/New_York a zone that is -05:00 in winter and -04:00 in summer
Storing "Europe/London" for a user is right, because it stores the rule. Storing "UTC+1" is wrong, because in six months the rule moves and the number does not.
This is what the IANA time zone database is for, and why its identifiers look like America/Los_Angeles rather than PST3. Three-letter abbreviations are ambiguous: CST is US Central Standard Time at UTC-6 and also China Standard Time at UTC+8, fourteen hours apart. The database is also maintained, which matters, because governments change these rules with a few weeks of notice and your runtime needs the update.
Our Timezone Converter works from IANA names, so conversions across a transition are correct rather than approximately correct.
The parsing trap that costs the most time
Here is the one worth memorising, because it looks like a typo and behaves like a bug.
A date-only string is interpreted as UTC. The same date with a time attached, and no offset, is interpreted in the machine's local zone1. So "2026-04-21" and "2026-04-21T00:00:00" are four hours apart on a machine in New York, and zero hours apart on a machine in London, and your test suite runs on a CI box set to UTC where they agree perfectly.
The space-separated form, "2026-04-21 14:40:00", is not a standard format at all. Both engines accept it and treat it as local, but the specification does not require that and MDN warns the behaviour is implementation-specific1.
Only two of those six strings mean the same thing everywhere: the one ending in Z and the one carrying an explicit offset.
The two hours that break every March and November
The gap. US Pacific time goes from 01:59:59 at -08:00 straight to 03:00:00 at -07:00 on 8 March 2026. Nothing reads 02:30 that day. A reminder set for it has no instant to fire at, and libraries disagree about whether to throw or quietly move it.
The fold. On 1 November 2026 the clock falls back, and 01:30 happens twice, one hour apart. The ambiguity lasts exactly one hour, and a log sorted by local timestamp is genuinely out of order across it.
And the transitions are not global. The EU moves on the last Sunday in March, three weeks after the US, so for those three weeks the offset between London and New York is not what either side's code assumes. Arizona mostly does not observe DST at all, Hawaii does not, and much of the tropics never has.
The rules that prevent all of this
Store an instant for the past, a rule for the future. Something that happened is a UTC timestamp. Something scheduled is a wall-clock time plus an IANA zone. "Monday 09:00 in New York, weekly" stored as a UTC instant drifts by an hour twice a year; stored as a rule it does not.
Never do arithmetic on local time. Adding 24 hours to a local wall-clock reading does not reliably reach the same time tomorrow. Add to the instant, then format.
Never parse a string without knowing its zone. See above. If it has no Z and no offset, its meaning depends on the machine.
Serialise to ISO 8601 with an offset.
2026-04-21T14:40:00Z UTC
2026-04-21T14:40:00.123Z with milliseconds
2026-04-21T10:40:00-04:00 the same instant, New York
Sortable as text, unambiguous, parsed by everything. Avoid MM/DD/YYYY versus DD/MM/YYYY, where 02/03/2026 is two different days depending on the reader, and avoid anything with no zone at all. Our Date Formatter converts between representations without losing the instant underneath.
What Temporal changes
The whole article above is a list of workarounds for a 1995 API. Temporal is the replacement, and it is now in browsers: both Chromium 147 and Firefox 148 expose it, and both accept a zoned string of the form 2026-03-08T01:30:00-08:00[America/Los_Angeles].
The important part is that Temporal makes the distinction this article has been labouring a type distinction rather than a discipline2:
Temporal.Instantis a moment, with no zone and no calendar.Temporal.ZonedDateTimeis a moment plus the zone it should be read in, serialised in RFC 9557 with the zone identifier in brackets, so the rule travels with the value.- The
Plaintypes are wall-clock readings that deliberately have no instant, which is exactly what a recurring appointment is.
Objects are immutable, arithmetic is explicit, and the string format carries the zone name rather than only an offset. That last point solves the recurring-event problem at the serialisation layer, which nothing before it did.
MDN still lists Temporal as limited availability2, so production code wants a polyfill for now. It is worth writing against anyway, because the API forces the questions this article says to ask.
Y2038, still worth a grep
A signed 32-bit count of seconds overflows at 2,147,483,647, which is 03:14:07 UTC on 19 January 2038, and wraps to December 1901. Most systems moved to 64-bit years ago. Embedded devices, old file formats and any schema that packed a timestamp into a 32-bit column did not.
The fix is trivial and the audit is not, which is the usual shape of these things.
Working across zones
Pick a reference zone and say so, because "Thursday 9 AM" is not information. Write timestamps with a label: "15 March, 14:00 UTC" survives being forwarded, "2 PM" does not. And for the daily question of what time it is somewhere else, the World Clock answers it faster than arithmetic.
UTC in storage, IANA names for rules, ISO 8601 with an offset on the wire. Those three cover almost everything, and Temporal is starting to make them the path of least resistance rather than a discipline you have to maintain.
Sources
Every number in this article traces to a source below. Where a claim could not be sourced, it was cut rather than softened.
- Primary sourceMDN Web Docs
That a date-only string is interpreted as UTC while a date-time string without an offset is interpreted in the local zone, and that non-standard date strings are parsed in implementation-specific ways that vary between browsers.
- Primary sourceMDN Web Docs
What Temporal replaces in the legacy Date object, the distinction between Instant, ZonedDateTime and the Plain types, serialisation via RFC 9557 with a bracketed time zone identifier, and that the API is not yet Baseline.
- Primary sourceIANA
That the tz database is the maintained source of time zone rules and identifiers such as America/Los_Angeles, updated as jurisdictions change their rules.
Topics
- Timestamps
- Timezones
- Datetime
- DST
- Iso 8601
Tools mentioned in this article
- Unix Timestamp Converter - Convert Unix timestamps to human-readable dates and back.
- Timezone Converter - Convert times between timezones instantly. Supports 28+ world timezones with DST handling.
- Date Formatter - Format any date in 12 patterns including ISO 8601, US, EU, RFC 2822, Unix timestamp and relative.
- World Clock - Live-updating clocks for multiple timezones. Add and remove cities to build your custom dashboard.
Get new tools by email
New tools and the occasional deep-dive, about once a month. No spam, no sharing your address, unsubscribe in one click.