Unix timestamps explained
A short reference on Unix timestamps — what the epoch is, why time is counted from 1970, the seconds vs milliseconds confusion, what happens in 2038, and why leap seconds quietly do not exist in Unix time.
The one-line definition
A Unix timestamp is the number of seconds (or, conventionally in modern systems, milliseconds) that have elapsed since 00:00:00 UTC on 1 January 1970, not counting leap seconds. That moment is called the Unix epoch. Everything in the Unix-time family — time_t, Date.now(), time.time(), Instant.now().getEpochSecond() — is counting from there.
1716241200 corresponds to 2024-05-20T22:00:00Z. 1716241200000 (with three extra zeros) is the same moment expressed in milliseconds.
Why 1970
Unix was developed at Bell Labs starting in 1969. The team picked the start of the next round year — 1 January 1970 — as the reference point for their time API in the first edition of the manual (1971). At the time the choice was practical: timestamps in 32-bit signed integers could cover roughly the next 68 years, which seemed like plenty.
No deep meaning. No astronomical significance. Just a recent round date that gave them enough headroom to ship.
Seconds vs milliseconds (the format confusion)
The original Unix time_t was an integer count of seconds. That convention persists in C, Go, Python's time.time() (returns a float, but the integer part is seconds), and most Unix-family languages.
JavaScript broke ranks and used milliseconds — Date.now() returns 13-digit numbers. Most modern JSON APIs follow whatever convention their authors picked: Slack uses seconds (as a string!), Stripe uses seconds, JIRA uses milliseconds, Linear uses ISO 8601 strings instead.
The result is a permanent format-detection problem. A reasonable heuristic:
- 10 digits — seconds. (Roughly 2001 to 2286 in this notation.)
- 13 digits — milliseconds.
- 16 digits — microseconds.
- 19 digits — nanoseconds.
If you have to guess, look at how big the number is: anything above ~`10^12` is almost certainly milliseconds or finer.
Leap seconds do not exist in Unix time
UTC has occasional leap seconds — extra seconds inserted (or, theoretically, removed) to keep atomic time aligned with the Earth's slightly irregular rotation. There have been 27 inserted since 1972, the most recent in December 2016. The next one is scheduled to be the last; the IERS plans to discontinue leap seconds after 2035.
Unix time pretends these don't exist. On a leap-second day, the second 23:59:60 either:
- Gets the same Unix timestamp as
23:59:59, and the next second00:00:00of the next day gets the timestamp that would have been correct, OR - The clock smears the extra second over a longer period (Google's approach), spreading it across about 20 hours
Either way, the count of Unix seconds between two arbitrary dates is not equal to the count of actual elapsed seconds when a leap second falls between them. The discrepancy is small — currently 27 seconds since 1972 — but for high-precision timing (financial trading, GPS, scientific instruments) it matters.
The Year 2038 problem
The original time_t was a 32-bit signed integer. The largest value it can hold is 2147483647, which corresponds to 03:14:07 UTC on 19 January 2038. One second after that, signed 32-bit overflow wraps to a large negative number, jumping back to roughly 1901.
This is the "Y2K38" or "Year 2038 problem." Modern systems use 64-bit time_t (which is good for about 292 billion years before the next wrap), but plenty of embedded devices, file formats, and legacy databases still use 32-bit values. The migration has been quietly going on for years; pockets of risk remain.
Timezone is not part of the timestamp
A Unix timestamp is always UTC. There is no "Unix timestamp in New York time." Timezones come into play only when you format the timestamp for display:
// Same moment, different displays
const ts = 1716241200000
new Date(ts).toISOString()
// → '2024-05-20T22:00:00.000Z'
new Date(ts).toLocaleString('en-GB', { timeZone: 'Europe/Tallinn' })
// → '21/05/2024, 01:00:00' (EEST, UTC+3)
The number is the same. The timezone determines how it is rendered.
ISO 8601 is the human-readable counterpart
1716241200 and 2024-05-20T22:00:00Z are the same moment in different notations. The ISO form is what you put in JSON for human readability; the Unix form is what you put in databases for storage efficiency and indexability.
Almost every modern API supports either at input time. For storage, integer Unix milliseconds is hard to beat: it sorts correctly as an integer, takes 8 bytes, no timezone ambiguity.
Try it
The timestamp converter at /tools/timestamp auto-detects whether you pasted seconds or milliseconds, and shows the moment in UTC, your local timezone, any IANA timezone, ISO 8601, and as a relative offset from "now." Helpful when you are debugging a log file with mixed timestamp formats.