Guide
Unix Timestamps Explained: Epoch, Precision, and the Year-2038 Problem
The world's most common time format is a 56-year-old hack with a 12-year fuse.
By Buğra SözeriPublished
A Unix timestamp is a single integer that pins a moment in time. It’s the most widely used time format in computing — every database, log line, JWT, and HTTP cookie ultimately leans on it. It’s also full of traps that don’t announce themselves until your data is already wrong.
What it is, precisely
A Unix timestamp is the number of seconds (or milliseconds, microseconds, nanoseconds — pick a unit) that have elapsed since 1970-01-01T00:00:00 UTC, commonly called “the Unix epoch.” Today that’s a number in the 1.7 billions for seconds, or 1.7 trillion for milliseconds.
You can convert a timestamp to and from a calendar date with our timestamp converter — paste any integer and see the UTC date, your local date, and the relative time.
Why 1970?
The choice isn’t profound. Bell Labs shipped Unix v1 in 1971 and needed an arbitrary recent date for the time counter. An earlier prototype counted 1/60-second ticks since 1971-01-01, but the 32-bit counter would have overflowed in just under 2.5 years. The team switched to whole seconds and backdated the epoch to 1970-01-01 so that prior-year dates could be represented as negative numbers. It stuck because every downstream system locked it in.
Precision: seconds, ms, μs, ns
Different layers of the stack use different units:
- Seconds — classic Unix
time(), JWTiat/expclaims, HTTPDateheaders, most spreadsheet exports. - Milliseconds — JavaScript
Date.now(), JavaSystem.currentTimeMillis(), Kafka record timestamps, MongoDBObjectId(the first 4 bytes are seconds-since-epoch, packed alongside other fields in BSON). - Microseconds — Postgres
TIMESTAMP, MySQLDATETIME(6), tracing libraries (Jaeger, OpenTelemetry). - Nanoseconds — Linux
clock_gettime(CLOCK_REALTIME), Gotime.Now().UnixNano(), etcd, recent OpenTelemetry exporters.
At an API boundary, never assume. 1700000000 is November 2023 if read as seconds, January 1970 plus 20 days if read as milliseconds. A quick heuristic: if the integer is roughly 10 digits, it’s seconds; 13 digits, milliseconds; 16 digits, microseconds; 19 digits, nanoseconds. Our timestamp tool auto-detects all four.
Leap seconds: the lie at the bottom
POSIX defines a Unix timestamp as “seconds since the epoch” while explicitly assuming every day has 86,400 seconds. Real UTC doesn’t. Since 1972, 27 positive leap seconds have been inserted to keep UTC aligned with Earth’s rotation. The most recent was June 30, 2017.
Strict POSIX behavior is to freeze the clock during a leap second: timestamp 1483228827is served for two seconds in a row. This breaks monotonicity and crashes anything that assumes timestamps are unique. Google’s alternative, “leap smearing,” spreads the extra second over a 24-hour window so that no individual second is repeated; AWS, Meta, and Microsoft now do the same. Two servers using different schemes can disagree by up to half a second around a leap event.
For 99% of applications this doesn’t matter. For anything ordering events at sub-second precision across multiple providers, it absolutely does.
The year-2038 problem
A signed 32-bit integer can hold values from −2,147,483,648 to +2,147,483,647. Interpreted as seconds since 1970-01-01 UTC, the upper bound is 2038-01-19T03:14:07Z. One second later, the counter wraps to the most-negative value, representing December 13, 1901.
Modern 64-bit operating systems already use 64-bit time_t, which doesn’t overflow for another 292 billion years. The exposure that remains:
- Embedded devices— automotive ECUs, industrial PLCs, medical implants. Many still use 32-bit time and aren’t updated.
- File formats — ext2/ext3 inode timestamps, classic ZIP (DOS format), older NTFS extended attributes.
- SQL columns — a column declared
INTto “save space” for epoch seconds. Audit your schemas now, not in 2037. - Legacy C code compiled against an old libc on 32-bit ARM. Migration to 64-bit
time_tis an ABI break and many vendors haven’t shipped it.
For a longer treatment, see our Unix timestamp glossary entry.
Unix time vs ISO 8601
ISO 8601 (and its Internet profile, RFC 3339) writes time as 2026-05-31T14:30:00Z. It’s human-readable, timezone-aware, and self-describing. Unix time is compact, sortable as an integer, and unambiguous about the actual instant — but says nothing about which timezone the writer intended for display.
Use ISO 8601 in APIs, logs, and anywhere a human will read the value. Use Unix integers in storage when space and arithmetic matter, or when sorting must be cheap. Many systems carry both — the integer for operations, the string for audit trails. See the ISO 8601 glossary entry for the full grammar.
Common pitfalls
Timezone-naive parsing
new Date("2026-05-31") in JavaScript parses as UTC midnight, but new Date("2026-05-31 14:00") (note the space, not a T) is parsed as local time on most engines. The resulting Unix timestamps differ by your offset. Always include the timezone designator (Z, +09:00) on inputs you don’t fully control.
Mixing units silently
A microservice that emits milliseconds talks to a downstream that expects seconds. The downstream sees timestamps in the year 55000 and silently writes them to the database. Always validate the magnitude of incoming timestamps against a plausible range.
Local-time epochs
Some legacy systems compute “seconds since 1970-01-01 local time.” This isn’t Unix time and breaks the instant a server is moved or daylight saving flips. If you inherit one of these, record the offset alongside the integer and convert to true UTC epoch at the boundary.
Try the converter
Paste any integer into our timestamp converter to see the UTC and local interpretations side by side, with auto-detection of seconds/ms/μs/ns. For batch conversion or extra precision controls, the datetime timestamp tool handles both directions.
Bottom line
Unix time is a great default because it’s compact, sortable, and unambiguous about the instant. It’s a terrible default the moment you forget which unit you’re in, which timezone you intend to display, or whether your storage is 32-bit. The epoch was a pragmatic choice in 1970; the year-2038 cliff is the bill coming due. Audit your integer columns, document your units, and don’t store local-time epochs.
Frequently asked questions
- Why January 1, 1970?
- Bell Labs picked it as a round, recent date when Unix v1 shipped in 1971. Earlier prototype versions used 1971-01-01 with 1/60-second ticks; the rollover from a 32-bit counter would have happened in about 2.3 years, so the team switched to whole seconds and backdated the epoch to 1970-01-01 UTC. It was practical, not theological.
- Are leap seconds counted in Unix time?
- No. POSIX defines a Unix timestamp as the number of seconds since the epoch assuming exactly 86,400 seconds per day, every day. Real UTC has occasionally inserted a leap second (most recently June 30, 2017). Most systems handle this by either freezing the counter for one second or 'smearing' the leap second across a longer interval (Google's approach). The result: the same Unix timestamp can correspond to two different real-world instants during a positive leap second.
- What exactly breaks in 2038?
- On January 19, 2038 at 03:14:07 UTC, a signed 32-bit seconds-since-epoch counter overflows to a negative number representing December 13, 1901. Any 32-bit system, embedded device, file format, or database column using a signed int32 for time will break. 64-bit Linux migrated years ago; the remaining exposure is in embedded systems, legacy file formats (ext2/3 inode timestamps, ZIP DOS timestamps), and SQL columns explicitly typed as INT.
- Should I store timestamps as integers or ISO 8601 strings?
- Integers if you'll do arithmetic and storage size matters. ISO 8601 strings if humans will read the data or you need to preserve the original timezone. Many systems store both — UTC epoch ms for sorting and arithmetic, plus the original tz-aware ISO string for audit. Don't store local-time epoch numbers; the moment a server moves timezones the data is silently corrupt.
- What's the difference between seconds, milliseconds, microseconds, and nanoseconds?
- Pure scale. JavaScript's Date.now() is milliseconds since epoch. Unix syscalls like clock_gettime(CLOCK_REALTIME) typically return nanoseconds. Database TIMESTAMP types vary by vendor — Postgres is microseconds, MySQL DATETIME(6) is microseconds, SQL Server is 100ns ticks. Always document the unit at the API boundary.
- Is a Unix timestamp timezone-aware?
- Yes and no. The timestamp itself is an absolute count of seconds since a fixed UTC instant, so it's unambiguous. But it carries no display timezone — converting back to a calendar date requires a timezone choice. A timestamp of 1700000000 is the same physical moment everywhere, but it renders as November 14 in Tokyo and November 13 in Los Angeles.
Sources & references
Authoritative references cited by this piece. Verified by Buğra Sözeri on the dates shown and re-checked at every deploy.
- POSIX.1-2017 (IEEE Std 1003.1) — Seconds Since the Epoch — Canonical definition of Unix time, including the explicit 86,400-seconds-per-day rule that excludes leap seconds(as of )
- RFC 3339 — Date and Time on the Internet: Timestamps — The widely-used Internet profile of ISO 8601, including 'Z' for UTC(as of )
- IANA Time Zone Database (tzdata) — Reference data used by every well-behaved system that converts Unix timestamps to local calendar dates(as of )
- Linux kernel — Y2038 status page — Tracking of remaining 32-bit time_t exposure in the kernel and supported architectures(as of )
- Google SRE — Leap seconds and smearing — Reference implementation of the leap-second smear approach now adopted by AWS, Meta, and Microsoft(as of )
Related
Published May 31, 2026