PRACTICAL GUIDE
Unix Timestamps Explained: Seconds, Milliseconds and Time Zones
How epoch time works, how to tell seconds from milliseconds at a glance, and the handful of mistakes that cause almost every date bug.
Last updated
One number, counting from one moment
A Unix timestamp is the number of seconds elapsed since midnight UTC on 1 January 1970, known as the epoch. It is a plain integer, which is exactly why it is everywhere: no format to parse, no locale to interpret, no ambiguity about whether 03/04 means March or April. Negative values represent times before 1970.
Seconds or milliseconds — read the length
Unix conventionally counts seconds, but JavaScript counts milliseconds, and mixing the two is the most common timestamp bug there is. The symptom is unmistakable: dates in 1970, or dates fifty thousand years in the future.
You can tell them apart by digit count. A present-day timestamp in seconds has 10 digits; the same moment in milliseconds has 13. Some systems go further, to microseconds at 16 digits or nanoseconds at 19.
A timestamp has no time zone
This trips up almost everyone at some point. The number itself is an absolute instant, identical everywhere on earth. Time zones enter only when you format it for display, and that is a property of the viewer, not of the value.
The practical rule follows: store and transmit instants as timestamps or as UTC strings, and convert to local time at the very last moment, in the interface. Storing local times is how you end up with records that shift by an hour twice a year.
Where you will run into them
JWT claims such as exp and iat are Unix timestamps in seconds — which is why a token decoder shows you a large integer rather than a date. Log files, database columns, HTTP cache headers, file modification times and most APIs use them too. Being able to convert one quickly is the difference between reading a log and guessing at it.
The 2038 problem is real but narrow
Systems that store the timestamp in a signed 32-bit integer overflow on 19 January 2038, wrapping around to 1901. Modern languages and 64-bit systems use a wider integer and are unaffected for a period longer than the age of the universe. It still matters for embedded devices, old file formats and database columns that were declared as a 32-bit integer years ago — and it can bite early, wherever code calculates a date some years into the future.
Leap seconds, briefly
Unix time pretends every day has exactly 86,400 seconds, which is not quite true of the earth's rotation. Occasional leap seconds are absorbed rather than counted, usually by repeating or smearing a second. For virtually all software this is irrelevant; for anything measuring precise intervals across such an event, it is worth knowing that the count is a convention rather than a perfect physical measure.
Frequently asked questions
Why does my date show as 1 January 1970?
Almost always a zero, a null treated as zero, or a millisecond value being interpreted as seconds — the last of which puts you within a few weeks of the epoch. Check the digit count of the input first.
Why is my date in the year 55000?
The mirror image: a millisecond timestamp interpreted as seconds. Divide by 1000, or tell the parser which unit it is receiving.
Should I store dates as timestamps or as text?
For an instant in time, a timestamp or a UTC ISO 8601 string are both good, and the string has the advantage of being readable in a database dump. For a calendar date with no time — a birthday, an invoice date — store it as a date, because attaching a time zone to it creates the off-by-one-day bug.
How do I get the current timestamp?
In a browser console or Node, Date.now() gives milliseconds and Math.floor(Date.now()/1000) gives seconds. In a Unix shell, date +%s. In SQL, the function varies by engine but is usually some form of extract epoch from now.