Unix time, explained
Updated 2026-08-28 ยท about 8 minute read
A Unix timestamp is a single number that unambiguously identifies a moment. That is its entire appeal: no time zones, no date formats, no ambiguity about whether 03/04 means March or April.
What a Unix timestamp is
It is the number of seconds elapsed since 00:00:00 UTC on 1 January 1970, a moment known as the Unix epoch.
1787000000 is a Wednesday in August 2026. 0 is the epoch itself.
Negative numbers work fine and point backwards โ -86400 is New Year's Eve
1969.
The advantages are real. It is one integer, so it sorts, compares and subtracts trivially: the gap between two moments is one subtraction, where doing the same with calendar dates means worrying about month lengths and leap years. It has no time zone, because it is always UTC. And it has no format ambiguity.
The disadvantage is equally real: no human can read it. That is what the timestamp converter is for โ paste a number and get a readable date, or the reverse.
Why 1970?
There is no deep reason. It is an arbitrary choice that stuck.
Early Unix at Bell Labs counted in sixtieths of a second from 1971, which with a 32-bit counter overflowed in about two and a half years. Moving to whole seconds bought far more range, and the engineers rounded the start back to the beginning of the previous decade. It was convenient, and Unix's spread made it universal.
Other systems chose differently, which is a reliable source of off-by-decades bugs. Windows file times count 100-nanosecond intervals from 1601. Excel counts days from 1900 โ and famously includes a non-existent 29 February 1900, deliberately, to stay bug-compatible with Lotus 1-2-3. GPS counts from 1980 and, unlike Unix time, does not adjust for leap seconds, so it currently runs 18 seconds ahead of UTC.
Seconds or milliseconds?
This is the practical bug you will actually hit.
Unix time is defined in seconds. But JavaScript's Date.now()
returns milliseconds, and because JavaScript is everywhere, millisecond
timestamps are everywhere too. Java does the same. Python's time.time() returns
seconds as a float.
Mix them up and you get a date in 1970 or a date in the year 56000. Both are obviously wrong, which is the good news โ this bug tends to be loud rather than silent.
Telling them apart by eye is easy once you know the trick: count the digits. A current timestamp in seconds is 10 digits. In milliseconds it is 13. Microseconds, which some databases use, is 16. The timestamp converter detects this automatically, but the digit count is worth memorising.
Ten digits will remain correct until November 2286, so it is a safe heuristic for a career.
The leap second fudge
Here is the detail that makes Unix time technically a lie: a Unix day is always exactly 86,400 seconds, and real days are not.
The Earth's rotation is slightly irregular, so UTC occasionally inserts a leap second to stay aligned with astronomical time. Twenty-seven have been added since 1972. Unix time ignores them โ it simply repeats or skips a second, so the same timestamp value can refer to two different moments during a leap second.
This is a deliberate trade. Making every day exactly 86,400 seconds means converting a timestamp to a date requires no lookup table of historical leap seconds, which would otherwise have to be updated on every machine forever. The cost is that Unix time is not a true count of elapsed seconds since 1970 โ it is about 27 seconds short.
Leap seconds have caused genuine outages, taking down Reddit, LinkedIn and Qantas systems in 2012. Large operators now use "leap smearing", spreading the extra second across a whole day so no clock ever jumps. In 2022 it was agreed to abandon leap seconds by 2035, which will eventually make this a historical curiosity.
The year 2038 problem
On 19 January 2038 at 03:14:07 UTC, a signed 32-bit integer holding Unix time runs out. The maximum value is 2,147,483,647; add one more second and it wraps to negative, and the date becomes December 1901.
It is the same shape of bug as Y2K, and like Y2K it is being fixed steadily rather than dramatically. Modern 64-bit systems use a 64-bit time value, which does not overflow for about 292 billion years. Linux moved to 64-bit time on 32-bit platforms in kernel 5.6. Most languages and databases are already fine.
What remains at risk is embedded and industrial equipment: devices with 32-bit processors and long service lives that nobody updates. Traffic controllers, medical devices, building systems, industrial sensors, older cars. Anything installed today with a twenty-year life is still being built with the problem in some cases.
It has already surfaced. Systems calculating thirty-year mortgages hit it in 2008. Anything projecting dates forward encounters it before 2038 does.
If you write software: use 64-bit time, and never store a timestamp in a 32-bit column.
Using timestamps well
- Store timestamps, display local time. Keep UTC internally and convert at the last moment. Storing local time is how you end up with a database that is an hour wrong for half the year.
- Say which unit you mean. Name fields
created_at_msrather thancreated_atif they are milliseconds. This costs nothing and prevents a whole class of bug. - Use ISO 8601 for anything a human reads โ
2026-08-28T14:30:00Zsorts as text and is unambiguous. Reserve raw timestamps for machines. - Never use a timestamp as a unique identifier. Two things can happen in the same second, or the same millisecond. Use a UUID.
- Be careful with durations. Subtracting timestamps gives elapsed seconds, which is correct โ but "one month later" is not a fixed number of seconds and must be done with calendar arithmetic. The date difference calculator handles that properly.
For scheduling across a team rather than converting a single moment, our guide to working across time zones covers why offsets move, and the world clock shows several zones at once. Pikkit has the rest of the developer tools.