Short answer: a Unix timestamp counts the seconds since 00:00:00 UTC on 1 January 1970, with no timezone attached to it at all. Ten digits is seconds; thirteen digits is the same number in milliseconds. If two timestamps for one event are out of step by exactly your UTC offset, one of them was written in local time.
Almost every confusing timestamp problem comes down to one of three things: the wrong unit, a missing timezone, or a clock that was never correct to begin with.
What a Unix timestamp counts
A Unix timestamp is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970, ignoring leap seconds. The instant it marks is unambiguous, because it carries no timezone at all — it is a count, not a date.
That is the whole design. A count of seconds is the same number in Tokyo, Lagos and São Paulo, which is exactly what you want from a machine-readable record of when something happened. The ambiguity only appears when someone converts that count into something human-readable and has to decide which clock to display it against.
0 → 1970-01-01T00:00:00Z
1735689600 → 2025-01-01T00:00:00Z
-86400 → 1969-12-31T00:00:00Z (negative values are valid)
The unit problem, which is the most common one
Modern systems increasingly record milliseconds. The same instant therefore has two completely different representations available:
| The instant | Seconds | Milliseconds |
|---|---|---|
| 2025-01-01 00:00:00 UTC | 1735689600 | 1735689600000 |
| Now (roughly, 2026) | 1.7 × 10⁹ | 1.7 × 10¹² |
The failure mode is easy to recognise once you know it. Take a millisecond value and read it as seconds, and you land somewhere in the year 56000. Take a second value and read it as milliseconds, and you land in January 1970. Both produce confident, specific, completely wrong dates.
Massive values are also the reason JavaScript's Date constructor misbehaves. It takes
milliseconds, so passing a second-based timestamp silently produces a date in 1970 rather than an error.
Telling them apart without guessing
Do not hardcode a year threshold — that breaks. The robust test is magnitude based, and it works because the two ranges do not overlap for any plausible date:
- Anything under about 10¹¹ is seconds. 10¹¹ seconds from 1970 is the year 5138.
- Anything at or above 10¹¹ is milliseconds. 10¹¹ milliseconds from 1970 is 1973.
So a value like 1735689600 is seconds, 1735689600000 is milliseconds, and both are
read correctly by the same rule. The converter here applies exactly that test and
shows you which one it decided you meant, so the guess is visible rather than silent.
The timezone problem, which is quieter
Timestamps themselves have no timezone. Their representation does, and it is very often missing.
Consider 2026-03-01 09:00:00. Without an offset this is not a moment in time — it is a wall clock
reading that could be nine different instants depending on where you are standing. Written properly it is either
2026-03-01T09:00:00+08:00 or 2026-03-01T01:00:00Z, and those are the same instant.
Two practices prevent nearly all of the resulting confusion:
- Store and transmit in UTC. Always. Convert to local time only at the point of display.
- Always include the offset when writing a date in text form. The trailing
Zin ISO 8601 means UTC and costs one character.
Local time is a presentation concern. The moment it is used as a storage format, you have introduced a value whose meaning depends on the reader's location, and it will eventually be read somewhere else.
Daylight saving, the special case
In timezones that shift their clocks, two things happen every year that break naive date arithmetic:
- One hour of local time does not exist — it is skipped when the clocks go forward.
- One hour of local time happens twice — it repeats when the clocks go back.
"Add 24 hours" and "add one day" are therefore not the same operation. Adding 86,400 seconds to an instant is well-defined. Adding one calendar day means something different across a DST boundary. If you are scheduling, use a library that understands the timezone database rather than doing arithmetic on the clock. If you are merely recording when something happened, store UTC and the problem disappears.
The third problem: clocks that were wrong
A timestamp records what the machine's clock said. If a server had drifted, or a container started with the host's clock unset, the recorded time is faithfully wrong — and no amount of conversion will fix it.
The tell-tale signs in a log:
- Events out of order relative to dependencies, where the log shows an effect before its cause.
- Timestamps clustered exactly on a round number, which usually means a clock was corrected in a step rather than gradually.
- Regular drift that grows over time, which points at a machine that was never synchronised against a time source.
Systems should sync from a network time source, and logs should distinguish between "when the event happened" and "when it was written down" — the second is often available when the first is not.
Leap seconds, in one sentence
Unix timestamps ignore them. The Earth's rotation is not perfectly regular, and UTC occasionally inserts a second to compensate; Unix time deliberately does not, so it runs slightly behind a strict UTC clock. For nearly all software this is irrelevant. It matters for astronomical calculations and for atomic time standards, and almost nowhere else.
A short protocol for anything timestamp-shaped
- Determine the unit before you convert. Apply the magnitude test, and check that the resulting year is plausible.
- Determine whether an offset is present. If not, work out from context which timezone was intended, and write it down so the next reader does not have to guess.
- Convert in a local tool if the values are from logs. Log lines routinely contain hostnames, internal IPs, session identifiers and user IDs alongside the timestamps, so it is worth not sending them anywhere.
- Compare across machines using UTC only.
The Unix timestamp converter handles the first two steps, showing local time, ISO 8601 and UTC side by side so there is no ambiguity about which one you are reading. It runs in the page, so no log line has to leave the machine it is already on.