The digit-count rule
Epoch values grow predictably, so their length is a reliable fingerprint. For any date you are realistically holding right now:
| Digits | Unit | Range it covers |
|---|---|---|
| 9 | seconds | 1973 – 2001 |
| 10 | seconds | 2001 – 2286 |
| 11–12 | ambiguous | far-future seconds, or 1970s milliseconds |
| 13 | milliseconds | 2001 – 2286 |
| 16 | microseconds | 2001 – 2286 |
| 19 | nanoseconds | 2001 – 2262 |
Ten digits and thirteen digits are the two you will meet almost every day, and they are impossible to confuse once you have counted them once.
Why APIs disagree in the first place
Unix has counted seconds since 1970 and its whole tool ecosystem followed. JavaScript's
Date and Java's System.currentTimeMillis() chose milliseconds,
and every language that grew up around the browser inherited that. Postgres exposes
microseconds internally; Go's time.UnixNano() and InfluxDB hand out
nanoseconds. None of these are wrong — they are just different, and a JSON field named
timestamp tells you nothing about which one you have. A MongoDB
ObjectId embeds its own creation time in seconds, right
next to a JavaScript ecosystem that expects milliseconds everywhere else — the exact
confusion this page exists to resolve.
The ambiguous 11–12 digit zone
Between ten and thirteen digits, the digit count genuinely cannot decide. An 11-digit value is either a seconds timestamp somewhere in the year 5138, or a milliseconds timestamp from 1973. Neither is impossible, so this page scores both readings by whether they land in a plausible year and labels the answer likely — never certain. If both readings are implausible, it says so rather than picking one.
Detecting the unit in code
// JavaScript — normalise anything to milliseconds
const toMs = (n) => (String(Math.abs(n)).length >= 12 ? n : n * 1000)
# Python — same rule, same caveat about the 11-12 digit zone
def to_seconds(n: int) -> float:
return n / 1000 if len(str(abs(n))) >= 12 else float(n)
Both snippets encode the same heuristic this page uses. Ship them with a comment: a heuristic that is right 99.9% of the time still needs to be recognisable when it is the 0.1%. For the conversion itself once the unit is settled, see epoch values in JavaScript, which counts in milliseconds, and epoch values in Python, which counts in seconds — the mismatch between those two defaults is what produces most of the values this page gets pasted.
Edge cases worth knowing
- Leading zeros. A CSV that pads values to a fixed width does not change the magnitude — the digit count above is taken after stripping them.
- Negative values. Perfectly valid: they count backwards from 1970. A negative timestamp is a pre-1970 date, not corrupted data.
-
Fractional values.
1786795200.123is seconds with a fractional millisecond part. Python'stime.time()returns exactly this shape. -
Sub-millisecond units. Microsecond and nanosecond readings are
truncated to milliseconds for display, because that is all a JavaScript
Datecan hold.
Frequently asked questions
Is a 13-digit timestamp seconds or milliseconds?
Milliseconds. A 13-digit epoch covers roughly 2001 to 2286 when read as milliseconds, which is where real data sits. Read as seconds the same value would land more than a quarter of a million years in the future, so 13 digits is unambiguous in practice. Divide by 1000 to get seconds.
How many digits is a Unix timestamp in seconds?
Ten, for any date from 2001 to 2286. Nine digits covers 1973 to 2001. The full ruler: 10 digits is seconds, 13 is milliseconds, 16 is microseconds, and 19 is nanoseconds. Ten and thirteen are the two you will meet almost every day, and they are impossible to confuse once you have counted them once.
Why can't an 11 or 12 digit timestamp be identified?
Between ten and thirteen digits the digit count genuinely cannot decide. An 11-digit value is either a seconds timestamp somewhere in the year 5138, or a milliseconds timestamp from 1973. Neither is impossible, so this page scores both readings by whether they land in a plausible year and labels the answer likely, never certain. If both readings are implausible, it says so rather than picking one.
Why do different APIs use different timestamp units?
Unix has counted seconds since 1970 and its whole tool ecosystem followed. JavaScript's
Date and Java's System.currentTimeMillis() chose milliseconds,
and every language that grew up around the browser inherited that. Postgres exposes
microseconds internally, while Go's time.UnixNano() and InfluxDB hand out
nanoseconds. None are wrong — but a JSON field named "timestamp" tells you nothing about
which one you have.
Can a Unix timestamp be negative?
Yes. Negative values count backwards from 1970, so a negative timestamp is a pre-1970
date rather than corrupted data. Two other cases are also valid rather than broken:
leading zeros from a fixed-width CSV do not change the magnitude, and a fractional value
such as 1786795200.123 is seconds with a fractional millisecond part —
exactly the shape Python's time.time() returns.
Where to go next
If the implausible reading is what your users are actually seeing, the 1970 debugger names the bug and gives you the fix. If you have a whole column of values in mixed units, the bulk converter detects the unit per row rather than making you split the file first.