Unix timestamp to date and time — 10-digit seconds, 13-digit milliseconds, local and UTC

Paste a 10-digit second or 13-digit millisecond timestamp and read off the local time, the UTC time and both ISO 8601 spellings; or pick a date and time and get its seconds and milliseconds back. How the digit count decides the unit, and where the famous 8-hour offset comes from, is explained below. Everything converts on your device.

—

Worked timestamps

You pasteSecondsMillisecondsUTC time
1735689600173568960017356896000002025-01-01 00:00:00
1735689600000173568960017356896000002025-01-01 00:00:00
1700000000170000000017000000000002023-11-14 22:13:20
0001970-01-01 00:00:00
The digit count decides the unit

What a Unix timestamp actually is

It is the amount of time elapsed since 1970-01-01T00:00:00 UTC (the epoch). The start point is an absolute instant, and the definition contains no timezone at all: 1735689600 is the same moment in Beijing and in New York, it only displays differently. That is why timestamps belong in databases and logs - ordering is correct by construction, syncing between systems is unambiguous, and nothing extra has to be recorded about which clock or which zone. They also ignore leap seconds, so an interval crossing one can be off by a second.

Seconds or milliseconds, decided by the digit count

Digits Almost always Example Note
10 seconds 1735689600 stays 10 digits until 2286
13 milliseconds 1735689600000 fixed width
16 microseconds - too big for a Date, so that length is refused

Defaults differ across ecosystems: Date.now() in JavaScript, System.currentTimeMillis() in Java and time.Now().UnixMilli() in Go give milliseconds; time() in PHP, date +%s on Linux, Go’s Unix() and MySQL’s TIMESTAMP give seconds; PostgreSQL stores microseconds internally. Counting digits is a heuristic - it covers almost all real data but cannot confirm what your source actually meant. So lengths that fit neither story (8, 9, 11, 12 digits) are refused outright. A silently guessed wrong unit is far harder to debug than an error message.

Why your colleague’s screen disagrees

Same timestamp, different reading: the difference is always the zone. The date box holds local wall-clock time, and it is read with this machine’s zone rules, daylight saving included, before the UTC instant is derived. A machine set to TZ=UTC turns the same input into a different timestamp. The convention that keeps teams sane: store UTC, transmit UTC, convert to local only when rendering - and set TZ=UTC on servers and containers rather than trusting the host default.

The trailing Z versus +08:00

Z marks a zero offset from UTC; +08:00 says those wall-clock minutes sit 8 hours ahead of it. So 2026-01-01T16:00:00Z and 2026-01-02T00:00:00+08:00 are the same instant whose date digits differ by one. A bare 2026-01-02T00:00:00 has no offset, so the reader decides - and that is where bugs are made: per spec JavaScript parses a T date-time as local, but new Date("2026-01-02") (date only) as UTC, and older Safari treated the T form as UTC too. Nothing is guessed: the fields are split and rebuilt with the local getters and setters, so there is only one reading.

Questions that keep coming back

Our times are 8 hours off - what do we check first? Decide which unit and which zone the stored value really is. If a row holds “local time written into a UTC column”, read it as UTC and render it as UTC; converting it again just adds the offset twice.

Why doesn’t February 30 raise an error anywhere else? Most runtimes roll it over quietly - new Date(2026, 1, 30) becomes March 2, and you notice much later. Here the fields are read back after assembly and compared, so a day that does not exist (or a spring-forward gap) fails loudly. In practice the browser’s own date picker usually refuses the value outright and leaves the box empty, so you will more often see “no result” than this message; the check exists for the cases where a value really does arrive (typed manually, another browser, written by code).

Timestamp column or datetime column? Prefer a real numeric timestamp, or a zone-aware type such as PostgreSQL timestamptz. A plain datetime records wall-clock time with no zone, which loses information as soon as data crosses one. Note that MySQL’s TIMESTAMP tops out in 2038 - use BIGINT for long-lived rows.

Everything is converted with the platform’s own date facilities, locally in your browser. What you type never leaves this device.

Support on PayPal