A Unix timestamp is the number of seconds elapsed since 00:00:00 UTC on 1 January 1970, a moment called the epoch. That is the entire definition. Everything else is consequences.
The tool Unix Timestamp Converter Open it →Seconds or milliseconds?
The single most common source of confusion. The original definition is in seconds, but JavaScript, Java and a great many logging and analytics systems count milliseconds instead. The same instant is therefore represented by two numbers differing by a factor of a thousand.
Count the digits:
| Digits | Unit | Example | Represents |
|---|---|---|---|
| 10 | Seconds | 1767225600 | 1 Jan 2026 |
| 13 | Milliseconds | 1767225600000 | 1 Jan 2026 |
| 16 | Microseconds | 1767225600000000 | 1 Jan 2026 |
Ten digits will remain the norm for seconds until November 2286. The classic symptom of getting it wrong: dates in 1970 (you divided when you should not have) or dates fifty thousand years out (you multiplied when you should not have).
Timestamps have no timezone
This is the concept that unlocks the rest. A timestamp identifies an instant — a single point on the universal timeline. It is not "3pm", it is the moment that was 3pm in Johannesburg and 1pm in London simultaneously.
So converting a timestamp to a different timezone does not change the timestamp. It changes only how you render it. Two servers on opposite sides of the world record the identical number for the same event.
The practical rule that falls out: store instants, render locally. Keep timestamps or UTC in your database, and apply the timezone at the moment you display something to a person. Storing local times is how you end up with an hour of duplicated or missing records every time daylight saving shifts.
The exception worth knowing: future events tied to local wall-clock time. A meeting at 9am next March should be stored as a local time plus a timezone name, not an instant — because if that region changes its daylight saving rules before then, the instant you calculated will be wrong but "9am" will still be right.
ISO 8601
When a timestamp needs to be human-readable, ISO 8601 is the format to use: 2026-01-01T00:00:00Z. The T separates date from time and the Z means UTC — "Zulu" in the phonetic alphabet. An offset can appear instead, as in +02:00.
Its advantages over local formats are practical: it sorts correctly as plain text, it is unambiguous about offset, and it sidesteps the 03/04/2026 problem, which is 3 April in most of the world and 4 March in the United States.
The 2038 problem
Systems that store the timestamp in a signed 32-bit integer can represent at most 2,147,483,647 seconds. That runs out at 03:14:07 UTC on 19 January 2038, after which the value overflows to negative and the date reads as December 1901.
It is the same shape of problem as Y2K, and like Y2K it is being fixed steadily rather than dramatically. Modern 64-bit systems have effectively unlimited headroom — around 292 billion years. The remaining risk sits in embedded devices, older file formats and database columns that were defined as 32-bit integers long ago and never revisited.
Worth checking now if you store timestamps as integers: anything calculating a date more than a decade ahead, such as an expiry or a maturity date, can hit the boundary well before 2038 arrives.
Leap seconds
Unix time pretends leap seconds do not exist. A day is defined as exactly 86,400 seconds, so when a leap second is inserted to keep clocks aligned with the Earth's rotation, Unix time repeats or holds a value rather than counting past it.
This means Unix time is not strictly a count of elapsed physical seconds since 1970 — it is off by the number of leap seconds inserted since. In exchange, the arithmetic stays trivial, which is a trade almost everyone is happy with. Large providers avoid the discontinuity by "smearing" the extra second across a whole day so no clock ever jumps.
In 2022 the international body responsible voted to stop inserting leap seconds by 2035, which will eventually make this a historical footnote.
Negative timestamps
Dates before 1970 are negative. -86400 is 31 December 1969. Most modern languages handle this correctly, but plenty of code assumes a timestamp is positive — validation that rejects negatives, or a database column defined as unsigned. If your data includes birth dates, historical records or anything pre-1970, test it explicitly.
Common bugs, in order of frequency
- Unit mismatch. Passing seconds to something expecting milliseconds. Check the digit count first, always.
- Local time where UTC was meant. Works perfectly on a developer machine set to the same timezone as the test data, then fails in production.
- Daylight saving. Adding 86,400 seconds is not the same as adding a day. Twice a year, in most of Europe and North America, a calendar day is 23 or 25 hours long.
- Assuming the server timezone. Servers are usually set to UTC, but not always, and "usually" is doing a lot of work in that sentence.
- Precision loss. Microsecond timestamps exceed JavaScript's safe integer range at 2⁵³, so they lose accuracy passing through JSON. Send them as strings.