What decoding actually involves
Turning a timestamp into a date is two steps, and they fail in different ways. Step one is scaling: deciding whether the integer is seconds, milliseconds, microseconds or nanoseconds and converting it to a single common unit. Step two is calendar arithmetic: taking that count and walking it out into a year, month, day and time, honouring the Gregorian leap-year rule and the fact that a Unix day is always exactly 86,400 seconds long.
Step two is boring and reliable — every date library on earth agrees on it. Step one is where the bugs live, because the raw number carries no unit and nothing will warn you. A wrong scaling factor does not produce an error; it produces a perfectly valid date on the wrong side of a century. That is why this page leads with the detection verdict rather than hiding it.
Every digit length, and the window it covers
This is the whole basis for auto-detection, computed rather than asserted. For each value length, the table below shows the unit Epochly assigns and the exact calendar range that length can express in that unit. Read down the "covers" column and the pattern is unmistakable: 10-digit seconds, 13-digit milliseconds and 16-digit microseconds all describe the same span of history, 2001-09-09 to 2286-11-20. They are the same window written at three resolutions, which is precisely why counting digits identifies the unit.
| Digits | Detected as | Value range | Covers (UTC) |
|---|---|---|---|
| 1 | seconds (s) | 0 9 | 1970-01-01T00:00:00.000Z 1970-01-01T00:00:09.000Z |
| 2 | seconds (s) | 10 99 | 1970-01-01T00:00:10.000Z 1970-01-01T00:01:39.000Z |
| 3 | seconds (s) | 100 999 | 1970-01-01T00:01:40.000Z 1970-01-01T00:16:39.000Z |
| 4 | seconds (s) | 1000 9999 | 1970-01-01T00:16:40.000Z 1970-01-01T02:46:39.000Z |
| 5 | seconds (s) | 10000 99999 | 1970-01-01T02:46:40.000Z 1970-01-02T03:46:39.000Z |
| 6 | seconds (s) | 100000 999999 | 1970-01-02T03:46:40.000Z 1970-01-12T13:46:39.000Z |
| 7 | seconds (s) | 1000000 9999999 | 1970-01-12T13:46:40.000Z 1970-04-26T17:46:39.000Z |
| 8 | seconds (s) | 10000000 99999999 | 1970-04-26T17:46:40.000Z 1973-03-03T09:46:39.000Z |
| 9 | seconds (s) | 100000000 999999999 | 1973-03-03T09:46:40.000Z 2001-09-09T01:46:39.000Z |
| 10 | seconds (s) | 1000000000 9999999999 | 2001-09-09T01:46:40.000Z 2286-11-20T17:46:39.000Z |
| 11 | seconds (s) | 10000000000 99999999999 | 2286-11-20T17:46:40.000Z 5138-11-16T09:46:39.000Z |
| 12 | milliseconds (ms) | 100000000000 999999999999 | 1973-03-03T09:46:40.000Z 2001-09-09T01:46:39.999Z |
| 13 | milliseconds (ms) | 1000000000000 9999999999999 | 2001-09-09T01:46:40.000Z 2286-11-20T17:46:39.999Z |
| 14 | milliseconds (ms) | 10000000000000 99999999999999 | 2286-11-20T17:46:40.000Z 5138-11-16T09:46:39.999Z |
| 15 | microseconds (µs) | 100000000000000 999999999999999 | 1973-03-03T09:46:40.000Z 2001-09-09T01:46:39.999Z |
| 16 | microseconds (µs) | 1000000000000000 9999999999999999 | 2001-09-09T01:46:40.000Z 2286-11-20T17:46:39.999Z |
| 17 | microseconds (µs) | 10000000000000000 99999999999999999 | 2286-11-20T17:46:40.000Z 5138-11-16T09:46:39.999Z |
Two rows are worth pausing on. Eleven digits still reads as seconds and reaches the
year 5138 — that is the headroom which makes the seconds window safe to extend past 10. And
twelve digits flips to milliseconds even though twelve digits of seconds is
arithmetically valid, because twelve digits of seconds would be the year 33,658 and no real system
emits that. Detection is a bet on which reading is plausible, and the table is the evidence behind
the bet. Force the unit with the s / ms / µs / ns buttons whenever you know better.
The four output formats, and when each one is the right answer
- ISO 8601 UTC —
2023-11-14T22:13:20.000Z. Sorts lexicographically in the same order it sorts chronologically, which makes it the correct choice for filenames, log lines and anything that will be compared as a string. The trailingZis not decoration; it is what makes the string unambiguous. - RFC 2822 —
Tue, 14 Nov 2023 22:13:20 +0000. The email format, and what an SMTPDate:header holds. Note the numeric+0000offset: the superficially similar HTTP date header uses the literal wordGMTinstead, so the two are not interchangeable despite looking alike. - Local time with the zone named — the line to quote when you are talking to a
person rather than a machine. Epochly prints the IANA zone identifier your browser resolved
(something like
Europe/Berlin) rather than an abbreviation, because abbreviations are ambiguous:CSTalone is three different offsets depending on the continent. - Relative — "3 hours ago". Best for triage, worst for records. Months and years in the relative label use 30-day and 365-day approximations, so treat it as a distance rather than a measurement.
Worked example: the row nobody could date
A support ticket quotes an updated_at of 1700000000 and asks why the
record "changed in the future". Decode it: ten digits, so seconds, so
2023-11-14T22:13:20.000Z. Nothing is in the future; the reporter was reading the
number as milliseconds in their head, which would put it 19 days after the epoch. Two people, one
number, two units — and the dashboard that rendered it as 1970 was making exactly the same mistake
in code.
The general procedure when a date looks wrong: paste the raw stored value here before touching the code. If Epochly's date is the one you expected, the storage is fine and the renderer is broken. If Epochly's date is also wrong, the value was written wrong and no amount of display fixing will help. That one test splits the problem in half in about five seconds.
Decoding one value without leaving your terminal
For a single value on a machine you already have open, three one-liners cover almost everything.
GNU date: date -u -d @1700000000. Python:
python3 -c "import datetime,sys;print(datetime.datetime.fromtimestamp(int(sys.argv[1]),datetime.timezone.utc))" 1700000000.
Node: node -e "console.log(new Date(1700000000*1000).toISOString())". All three expect
seconds, so a 13-digit value needs dividing first — which is the entire reason the digit
rule is worth memorising. The full ten-language reference lives on the
main converter page.
Related conversions
- Date to Unix timestamp — the opposite direction, including how the same wall clock maps to eleven different epoch values across eleven zones.
- Milliseconds to date — the 13-digit case on its own, with both readings of five real literals printed side by side.
- Current Unix timestamp — the live count and the milestone table, including the 2038 ceiling.
- Discord timestamp generator — turn a decoded instant into a tag that renders in each reader's own zone.