⚡Utilvy
2026-10-28

Unix Timestamp Explained: Why 10 and 13 Digits Differ

A Unix timestamp counts the time elapsed since January 1, 1970 UTC, known as the Unix Epoch. A 10-digit timestamp is measured in seconds, while a 13-digit one is in milliseconds, which is the same moment expressed a thousand times larger. Knowing which unit you have is what decides whether a conversion lands in 2026 or back in 1970.

What the Digit Count Actually Tells You

A Unix timestamp is just a counter that started at 00:00:00 UTC on January 1, 1970. The unit of that counter depends on who generated it. Seconds are the classic Unix convention, so most command-line tools, databases and PHP functions produce 10-digit values. JavaScript and Java count in milliseconds, so they emit 13 digits. The digit count is not a different "format" you need to memorize — it is the same counter with the decimal point moved.

The digit count also pins down the era, because timestamps only ever grow. A 9-digit value in seconds is older than September 2001; a 10-digit value starts at exactly 1,000,000,000 seconds, which fell on September 9, 2001 at 01:46:40 UTC. Milliseconds crossed into 13 digits at the same instant, since 1,000,000,000 seconds and 1,000,000,000,000 milliseconds describe one moment.

Here is the full mapping. All four example values below encode the same instant, January 28, 2026 at 02:40 UTC:

| Digits | Unit | Example value | Date covered | |---|---|---|---| | 9 | seconds | 831826800 | May 1996 – Sep 2001 | | 10 | seconds | 1769568000 | Sep 2001 – Nov 2286 | | 13 | milliseconds | 1769568000000 | Sep 2001 – Nov 2286 | | 16 | microseconds | 1769568000000000 | Sep 2001 – Nov 2286 | | 19 | nanoseconds | 1769568000000000000 | Sep 2001 – Nov 2286 |

Notice the pattern: each extra unit of precision adds exactly three digits, because seconds, milliseconds, microseconds and nanoseconds differ by a factor of 1,000. That is why the digit count is such a reliable unit detector — there is no ambiguity between a 10-digit and a 13-digit value.

Where Each Format Comes From

Knowing the source helps you guess the unit before you even count the digits:

  • Seconds (10 digits): the Unix date +%s command, C's time(), PHP's time(), MySQL's UNIX_TIMESTAMP(), and Python's time.time() (returned as a float). Most REST APIs built on Unix conventions also use seconds.
  • Milliseconds (13 digits): JavaScript's Date.now(), Java's System.currentTimeMillis(), Kafka message timestamps, and countless JSON APIs that were designed in a browser or JVM context. PostgreSQL's EXTRACT(EPOCH FROM ...) returns seconds, but clock_timestamp() in Java drivers often arrives in milliseconds.
  • Microseconds (16 digits) and nanoseconds (19 digits): high-resolution logging and performance tracing. Python's time.time_ns(), Go's UnixMicro() and UnixNano(), and .NET's DateTime.Ticks (18 digits at 100-nanosecond resolution) all exist to order events that happen inside the same millisecond.

Step-by-Step: Converting Either Format Correctly

Step 1 — Count the digits. This is the whole diagnosis. 10 digits means seconds, 13 means milliseconds, 16 microseconds, 19 nanoseconds. Do this before touching any conversion function.

Step 2 — Normalize to one unit in code. Every date library has a preferred input; give it what it wants instead of hoping it guesses:

// JavaScript expects milliseconds
const digits = String(ts).length;
const ms = digits >= 13 ? ts : ts * 1000;   // seconds input gets promoted
new Date(ms).toISOString();
# Python's datetime expects seconds
from datetime import datetime, timezone

def to_datetime(ts: int):
    s = str(ts)
    if len(s) >= 19: ts = ts / 1_000_000_000
    elif len(s) >= 16: ts = ts / 1_000_000
    elif len(s) == 13: ts = ts / 1000
    return datetime.fromtimestamp(ts, tz=timezone.utc)

Step 3 — Sanity-check the year you land in. A timestamp from 2026 starts with 17, whether it is 10 or 13 digits (1769... or 1769...000). If your conversion returns something in January 1970, you fed a seconds value into a millisecond parser: new Date(1769568000) gives January 21, 1970. If it returns a year in the distant future or throws an out-of-range error, you did the opposite.

Step 4 — Name your fields with the unit. The most common timestamp bug is not a bad conversion — it is two systems disagreeing about units. Use created_at_ms and expires_at_s instead of a bare timestamp, and the bug becomes impossible to write.

Step 5 — Beware the double conversion. Passing a millisecond value through a seconds-based parser twice (or a seconds value through a multiplier twice) silently produces dates decades off. If a converted date looks implausible, recompute from the raw source value, never from the already-converted one.

Why do JavaScript and Java use 13 digits?

Both platforms fixed on millisecond precision for their internal date types decades ago — JavaScript's Date and Java's original java.util.Date both store milliseconds since the epoch in their spec. Milliseconds were precise enough for UI timers and file timestamps, and the wider range conveniently pushes overflow far beyond the 32-bit seconds limit, which runs out on January 19, 2038. Nothing deeper than that; it is a historical default that every API built on those platforms inherited.

Why did my conversion return January 1970?

Because the parser interpreted your seconds as milliseconds. A value of 1.7 billion milliseconds is only about 20 days after the epoch, so any seconds-era timestamp fed to new Date() or Java's Date(long) lands in January–February 1970. Divide nothing — instead multiply the input by 1,000 before passing it, or use the digit-count check from Step 1. Also watch for Excel, which uses an entirely different system: days since 1900, not seconds since 1970.

Do 16-digit timestamps mean anything is broken?

No. Sixteen digits is simply microseconds, which show up when a system logs events with sub-millisecond precision — performance traces, database change streams, ordering within the same millisecond. Divide by 1,000,000 for seconds and the value converts like any other. If you see 16 digits where you expected 13, someone upgraded the logging precision, not the clock.

The Bottom Line

The digit count is the unit: 10 digits is seconds, 13 is milliseconds, 16 is microseconds, 19 is nanoseconds. Count first, normalize second, sanity-check the year third — and name your fields with the unit so the ambiguity never enters your codebase. When you want a quick, reliable conversion without writing code, paste the value into a Unix timestamp converter that accepts both 10- and 13-digit input. And if you are hunting down a timestamp inside a raw API payload, running it through a JSON formatter first makes the field you need easy to spot.

Try these tools