Unix timestamp seconds vs milliseconds — how to tell them apart
On this page
A Unix timestamp is one integer. The same instant can be 10 digits or
13 — seconds or milliseconds — and most languages accept either without
complaining. Pass the wrong one to new Date() and you get January 1970,
not a parse error.
This page is how to tell the units apart, why the mismatch keeps breaking production, and how to convert epoch to a date without guessing. Paste a number into the converter to see every format at once. It runs in your browser. Nothing is uploaded. There is no account.
What an epoch timestamp is
Unix time (also “epoch time”) counts from one fixed instant: 1970-01-01 00:00:00 UTC. The integer is timezone-independent. Two machines that agree on the number agree on the instant. Local clocks and daylight saving only appear when you format that integer for a human.
The original unit is seconds. 0 is the epoch. 1735689600 is
2025-01-01 00:00:00 UTC. Subtract two timestamps and you get a duration
in the same unit. That is why logs, databases, JWT exp / iat / nbf,
and most REST APIs still speak seconds.
For a longer primer, see What is Unix epoch?. To watch the current value tick, open the live now-clock. The number is not a calendar — it does not know months, timezones, DST, or leap seconds. Those are display problems, not part of the integer.
10 digits vs 13 digits (sec vs ms) — and when µs/ns show up
For any date in a working lifetime, digit count is a reliable tell:
Unit Example (2025-01-01 00:00:00 UTC) Typical digits
Seconds 1735689600 10
Milliseconds 1735689600000 13
Microseconds 1735689600000000 16
Nanoseconds 1735689600000000000 19
10 digits → seconds. C time_t, Python time.time(), Go Unix(),
PostgreSQL EXTRACT(EPOCH ...), MySQL UNIX_TIMESTAMP(), most APIs.
13 digits → milliseconds. JavaScript Date.now(), new Date(ms),
Java System.currentTimeMillis(), many metrics and real-time systems.
16 digits → microseconds. Postgres clock_timestamp(), Go
UnixMicro(), some time-series stores.
19 digits → nanoseconds. Go UnixNano(), modern Linux
st_mtim.tv_nsec, some tracing systems.
Negative numbers are valid — instants before 1970. Count the digits of
the absolute value the same way. A fractional value like
1735689600.123 is still seconds; the fraction is the sub-second part.
The digit heuristic holds until year ~5138. An 11- or 12-digit number is usually a bug — convert it both ways before you trust it.
Off-by-1000 bugs that break production
The mismatch does not throw. It produces a date that looks like a date.
// API returned Unix seconds. JavaScript Date expects milliseconds.
const ts = 1735689600;
const date = new Date(ts);
date.toISOString();
// → "1970-01-21T02:08:09.600Z" ← 21 days after the epoch, not 2025
A 10-digit second value, treated as milliseconds, lands in January 1970. A 13-digit millisecond value, treated as seconds, lands around year 50,000. Reviewers miss both because there is no exception.
What that looks like in production:
- “Updated 55 years ago” in a UI that rendered
new Date(seconds). - Cache TTLs that expire immediately (or never) because expiry math mixed units.
- Auth windows that reject every request when
Date.now()(ms) is compared totime.Now().Unix()(seconds) against a 60-second skew budget. The difference is about 1.7 trillion. - Tokens that “look valid” locally and fail on the server because
expis specified in seconds but the client set it fromDate.now().
The fix is mechanical. Name the unit, then scale once:
function dateFromUnixSeconds(s) {
return new Date(s * 1000);
}
function dateFromUnixMs(ms) {
return new Date(ms);
}
If you are designing an API, put the unit in the field name
(created_at_seconds, created_at_ms) and do not mix units in the same
payload. If you are reading an unknown number, count the digits before
you pass it to a constructor.
How this converter auto-detects
The Unix timestamp converter does not ask you to pick seconds or milliseconds. It looks at magnitude, then shows every common representation at once.
|n| < 10^11 → seconds (covers through year ~5138)
|n| < 10^14 → milliseconds
|n| < 10^17 → microseconds (scaled down to ms)
|n| ≥ 10^17 → nanoseconds (scaled down to ms)
Paste 1735689600 and it reports Unix seconds. Paste
1735689600000 and it reports Unix milliseconds. Sixteen- and
nineteen-digit values are treated as µs and ns and converted down so the
date is still right.
You also get ISO 8601 UTC, local time, RFC 2822, day of week, and a
new Date(...) constructor you can copy. Conversion runs in the page —
Date.now() and new Date(...). Open DevTools → Network if you want to
confirm nothing is uploaded. No signup.
DST and timezone display caveats
The integer is UTC. Daylight saving does not change it. When US clocks “spring forward,” Unix time keeps counting one second per second. Only the local display jumps.
That is why this converter always shows two clocks:
- ISO 8601 UTC — the unambiguous instant (
2025-01-01T00:00:00.000Z). - Local —
toLocaleString()plus the offset your browser reports (UTC-08:00,UTC+09:00, …). The timezone name is in the footer.
A few display traps that are not unit bugs:
- Date-only strings are ambiguous.
"2025-01-01"is midnight UTC in some parsers and midnight local in others. Prefer a full ISO string withZor an offset. - DST gaps and overlaps. In US zones, 2:00–3:00 AM does not exist in March and happens twice in November. Loop in UTC; convert at the edge.
- The offset is not the timezone.
UTC-08:00in January andUTC-07:00in July can be the same IANA zone (America/Los_Angeles). Store the instant, not “PST” as if it were permanent. - Leap seconds are invisible in Unix time. Do not expect
23:59:60from a Unix timestamp.
If local time looks “off by an hour,” check the offset pill before you assume a seconds-vs-milliseconds mix-up. Off-by-1000 is a 1970-or-year-50000 error. Off-by-one-hour is almost always display.
Related on this host: What is Unix epoch?, the live now-clock, and the Year 2038 problem.
Tools
- Unix timestamp converter — paste a number and see whether it was read as seconds or milliseconds.
- Current Unix timestamp (live) — seconds and milliseconds for this instant, side by side.