Unix Time Explained: Epoch, Milliseconds, and the 2038 Problem
Every timestamp you touch eventually reduces to one integer: the number of seconds since 00:00:00 UTC on 1 January 1970. Unix time — the epoch — is the quiet standard underneath log lines, database columns, cache keys, and JWTs, and the source of a steady stream of bugs: off-by-a-factor-of-1000 errors, timezone surprises, and the much-discussed 2038 wall. This article covers the epoch itself, seconds versus milliseconds, the 2038 wall, and how languages expose both. To convert a value you already have, use the timestamp converter.
What epoch time counts
Unix time counts elapsed seconds, not calendar time. The counter started at 1970-01-01T00:00:00Z, and every value is interpreted in UTC — there is no local timezone inside the epoch itself. Two consequences follow. First, epoch values are timezone-agnostic: the same integer means the same instant everywhere on Earth. Second, the count ignores leap seconds: POSIX time defines every day as exactly 86,400 seconds, so the epoch now trails official UTC by roughly 27 seconds.
Because the counter is a plain integer, negative values mean dates before 1970 — the Apollo 13 mission shows up as a negative epoch. There is no year-zero subtlety and no DST transition to resolve: just arithmetic, which is also why a raw epoch is useless for display until someone attaches a timezone.
Seconds vs milliseconds: telling them apart
Most epoch bugs in production are unit bugs, not logic bugs. Seconds and milliseconds differ by three orders of magnitude, and mixing them turns a valid timestamp into either 1970 or a date tens of thousands of years out.
The digit count is the fastest heuristic: a seconds timestamp has been ten digits since 2001 and stays ten digits until 2286; a milliseconds timestamp has been thirteen digits over the same span. So 1781000000 is seconds and 1781000000000 is milliseconds. Microseconds push to sixteen digits and nanoseconds to nineteen.
The confusion persists because JavaScript made milliseconds the default: Date.now() returns thirteen digits, so a value copied straight from the browser into Python or SQL is off by 1000x. The fix is mechanical — multiply or divide by 1000, and put the unit in the variable name (created_at_ms, never created_at). To sanity-check any value, paste it into the timestamp converter: a result in 1970 means milliseconds were read as seconds.
The 2038 problem, practically
The 2038 problem is an overflow in a specific data type, not in the concept of Unix time. A signed 32-bit integer holds up to 2,147,483,647; that many seconds after the epoch is 03:14:07 UTC on 19 January 2038. One second later the counter wraps negative, and affected systems jump back to 1901.
The blast radius is smaller than headlines suggest. Anything running a 64-bit time_t — every mainstream server OS and 64-bit runtime — is safe until the year 292,277,026,596. The exposure sits in three places: 32-bit embedded firmware, legacy databases and file formats that stored time as a 32-bit int, and old scheduled jobs with hardcoded date arithmetic. MySQL's TIMESTAMP is the famous example: epoch-based and capped at 2038, which is why DATETIME exists. New schema should use 64-bit integers or ISO-8601 strings.
Epoch in databases and APIs
Every mainstream language exposes the current epoch in one call; the unit is the thing to memorize:
| Language / system | Call | Unit |
|---|---|---|
| Python | time.time() | float seconds |
| JavaScript | Date.now() | milliseconds |
| Java | Instant.now().getEpochSecond() | seconds |
| Go | time.Now().Unix() | seconds |
| PHP | time() | seconds |
| SQLite | strftime('%s','now') | seconds |
| PostgreSQL | extract(epoch from now()) | float seconds |
When an API accepts epoch input, the contract must state the unit. When it emits epoch output, convert deliberately: milliseconds handed to a seconds-expecting consumer produce a date in the year 56000, not a crash — which is why these bugs survive testing. For human-readable output, run values through the epoch-to-date tool, and remember that display conversion needs a timezone — the epoch is UTC and your users are not. The timezone converter handles that last step.
Timestamp Converter — convert any epoch value between Unix time, ISO-8601, and human-readable dates, in both seconds and milliseconds.
Related tools: Epoch to Date · Timezone Converter