Skip to content
Timekeeping

Unix Time Explained — and the Year 2038 Problem

Unix time counts seconds since 1970-01-01 00:00 UTC, ignoring leap seconds. How it works, seconds vs milliseconds, notable timestamps, and why 32-bit clocks fail in 2038.

Unix time is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970, not counting leap seconds. It is a single integer — the same everywhere in the world at a given instant — which is why operating systems, databases and file formats use it to store time. The current value is shown live on the Unix time page.

The year 2038 problem comes from storing that integer in a signed 32-bit variable: the largest value it can hold, 2,147,483,647, is reached at 03:14:07 UTC on 19 January 2038. One second later, the counter overflows.

How Unix time works

The starting point, 1970-01-01T00:00:00Z, is called the Unix epoch. Times after it are positive; times before it are negative.

Unix timeUTC date and time
01970-01-01 00:00:00
86,4001970-01-02 00:00:00
−86,4001969-12-31 00:00:00
1,792,641,0682026-10-22 03:51:08

Unix time has no time zone. 1,792,641,068 is the same instant in London, Tokyo and New York; time zones come in only when the number is turned into a local date and time for display. This is what makes it useful for storage and comparison: subtracting two Unix times gives the seconds between them, with no daylight saving or offset to worry about.

Unix time ignores leap seconds

POSIX, the standard that defines Unix time, specifies it with a formula that treats every day as exactly 86,400 seconds. A date’s Unix time is computed from the year, day of year, hour, minute and second as though leap seconds did not exist.

UTC, however, occasionally has a 61-second minute. A leap second such as 2016-12-31T23:59:60Z has no Unix timestamp of its own: 2017-01-01T00:00:00Z is 1,483,228,800, exactly 86,400 × 17,167 days after the epoch, as if the extra second never happened. During the leap second itself, systems either repeat a timestamp, pause the clock, or “smear” the extra second across many hours so it never appears.

Two consequences follow:

  • Unix time is not a true count of elapsed SI seconds. 27 leap seconds have been added to UTC since 1972, and Unix time does not include any of them.
  • In exchange, converting between Unix time and a calendar date is pure arithmetic. Every minute has 60 seconds, every day 86,400, so timestamp % 86400 is always the seconds since UTC midnight.

The difference between UTC and atomic time is covered in UTC vs GMT.

Seconds, milliseconds and other units

Unix time is classically in seconds, but many systems count finer units from the same epoch:

UnitDigits todayExample (same instant)Used by
Seconds101792641068C time(), Python int(time.time()), PHP time(), most APIs
Milliseconds131792641068323JavaScript Date.now(), Java System.currentTimeMillis()
Microseconds161792641068323000some databases and tracing tools
Nanoseconds191792641068323000000Go UnixNano(), some tracing and logging systems

If a converter shows a date in 1970 or tens of thousands of years in the future, the unit is almost certainly wrong. Seconds-based timestamps have had 10 digits since 9 September 2001 and will keep 10 digits until 20 November 2286.

Notable Unix timestamps

Unix timeUTCNote
1,000,000,0002001-09-09 01:46:40first 10-digit timestamp
1,234,567,8902009-02-13 23:31:30
1,483,228,8002017-01-01 00:00:00just after the most recent leap second
2,000,000,0002033-05-18 03:33:20
2,147,483,6472038-01-19 03:14:07largest signed 32-bit value (2³¹ − 1)
4,294,967,2952106-02-07 06:28:15largest unsigned 32-bit value (2³² − 1)

All of these can be checked in the Unix time converter or the time calculator.

The year 2038 problem

For decades, the C type time_t that holds Unix time was a signed 32-bit integer on most systems. Its range is −2,147,483,648 to 2,147,483,647 seconds from the epoch:

  • Last representable moment: 2,147,483,647 = 2038-01-19T03:14:07Z.
  • One second later: the value overflows to −2,147,483,648, which decodes as 1901-12-13T20:45:52Z.

A system affected by the bug does not stop; it jumps back 136 years. Certificates appear not yet valid, timeouts compute as negative, scheduled jobs fire wrongly or never, and sorted records go out of order. Calculations that look into the future can fail before 2038: anything computing a date 20 years ahead, such as a long loan term or a certificate expiry, has been able to exceed the limit since 2018.

What has been fixed

  • 64-bit systems. On 64-bit Linux, BSD, macOS and Windows, time_t is 64 bits. A signed 64-bit count of seconds lasts for roughly 292 billion years in each direction, so the problem does not arise in the kernel or C library on these platforms.
  • The Linux kernel on 32-bit hardware. Linux 5.1 added new system calls that use 64-bit time on 32-bit architectures, and Linux 5.6 (2020) completed the kernel work so that 32-bit systems can run past 2038, provided user space is built for 64-bit time.
  • The C library. glibc 2.34 (2021) added support for a 64-bit time_t on 32-bit platforms such as x86 where it is traditionally 32-bit. It is opt-in: programs are compiled with -D_TIME_BITS=64, which also requires -D_FILE_OFFSET_BITS=64. Other C libraries have made similar changes, and Linux distributions have been rebuilding their 32-bit packages this way.

What is still at risk

The kernel and C library are only part of the picture. Problems remain wherever a 32-bit timestamp is baked into something that is hard to change:

  • Embedded and long-lived devices — industrial controllers, vehicles, routers, medical and building systems — often run 32-bit processors with old software and may still be in service in 2038.
  • File formats and network protocols that define a 32-bit seconds field. Changing the field breaks compatibility, so these need format revisions.
  • Databases. For example, MySQL’s TIMESTAMP type has a documented upper limit of 2038-01-19 03:14:07 UTC; DATETIME does not have this limit.
  • Application code that stores time in an int, a 32-bit database column, or a binary record — regardless of what the operating system does.

Unlike Y2K, the cutoff is a precise instant, and the fix is mostly mechanical: use a 64-bit type everywhere a timestamp is stored, transmitted or computed. A countdown to 2038-01-19 03:14:07 UTC is a blunt reminder of how much time is left.

Getting the current Unix time

// JavaScript
Math.floor(Date.now() / 1000);       // seconds
Date.now();                          // milliseconds
# Python
import time
int(time.time())                     # seconds
time.time_ns()                       # nanoseconds
# Shell (Linux, macOS, BSD)
date +%s
date -u -d @2147483647               # GNU: convert a timestamp to a date
// Go
time.Now().Unix()                    // seconds
time.Now().UnixMilli()               // milliseconds
// Java
java.time.Instant.now().getEpochSecond();
System.currentTimeMillis();          // milliseconds
// PHP
time();
-- PostgreSQL
SELECT floor(extract(epoch FROM now()));
SELECT to_timestamp(2147483647);     -- timestamptz: 2038-01-19 03:14:07+00 (in a UTC session)

-- MySQL
SELECT UNIX_TIMESTAMP();

To turn a Unix time into a readable, unambiguous string, format it as ISO 8601 in UTC, for example 2038-01-19T03:14:07Z. The ISO 8601 guide shows how in each language.

Sources

  1. POSIX.1 (The Open Group Base Specifications) — Seconds Since the Epoch
  2. glibc 2.34 release announcement
  3. Linux kernel mailing list — y2038: core, driver and file system changes (Linux 5.6 pull request)
  4. MDN — Date.now()

Dates, offsets and astronomical times quoted here are computed with the same code that powers the site's tools — see data sources and methods. Found an error? Tell us.

More related articles