Epoch Timestamps Explained: How Unix Time Works (and Why It Breaks)

17 Jun 2026 1,066 words

Epoch Timestamps Explained: How Unix Time Works (and Why It Breaks)

An epoch timestamp — also called Unix time or POSIX time — is the number of seconds that have elapsed since January 1, 1970 00:00:00 UTC, excluding leap seconds. It is a simple integer that represents a precise moment in time, independent of timezones and calendar systems. This simplicity makes it the standard way computers exchange time information, but it also has well-known limitations and pitfalls that every developer should understand.

How Unix Time Works

Unix time counts forward from the epoch. One day equals 86,400 seconds (24 × 60 × 60). The timestamp increases by exactly one per second regardless of timezone, daylight saving, or leap years.

Timestamp 0        → 1970-01-01 00:00:00 UTC
Timestamp 86400    → 1970-01-02 00:00:00 UTC
Timestamp 1000000  → 1970-01-12 13:46:40 UTC
Timestamp 1782000000 → 2026-06-17 00:00:00 UTC
// JavaScript — get current Unix timestamp
const nowInSeconds = Math.floor(Date.now() / 1000);
console.log(nowInSeconds);

// Convert timestamp to date
const date = new Date(nowInSeconds * 1000);
console.log(date.toISOString());
// PHP — get current Unix timestamp
echo time();             // seconds since epoch
echo microtime(true);    // seconds with microsecond precision

// Convert timestamp to date
echo date('Y-m-d H:i:s', 1782000000);

Seconds vs Milliseconds: A Common Source of Bugs

One of the most frequent timestamp-related bugs is confusing seconds with milliseconds. JavaScript's Date.now() returns milliseconds, while PHP's time() returns seconds. Many databases store timestamps in seconds, and many APIs use milliseconds.

System Unit Example Value Date
Unix / POSIX Seconds 1782000000 2026-06-17
JavaScript Date.now() Milliseconds 1782000000000 2026-06-17
Java System.currentTimeMillis() Milliseconds 1782000000000 2026-06-17
PHP time() Seconds 1782000000 2026-06-17
Python time.time() Seconds (float) 1782000000.123 2026-06-17
// ❌ Wrong — treating milliseconds as seconds
const timestamp = 1782000000; // this is in seconds
const wrongDate = new Date(timestamp); // interprets as milliseconds
console.log(wrongDate.toISOString()); // 1970-01-21 — completely wrong

// ✅ Correct — multiply by 1000
const correctDate = new Date(timestamp * 1000);
console.log(correctDate.toISOString()); // 2026-06-17
import time
from datetime import datetime

# ❌ Wrong — forgetting to divide milliseconds
millis = 1782000000000
wrong = datetime.fromtimestamp(millis)  # ValueError: year out of range

# ✅ Correct
correct = datetime.fromtimestamp(millis / 1000)
print(correct)  # 2026-06-17 00:00:00

The Year 2038 Problem

Unix time uses a signed 32-bit integer, which has a maximum value of 2,147,483,647. On January 19, 2038 at 03:14:07 UTC, the timestamp will reach this limit. One second later, a 32-bit signed integer wraps to −2,147,483,648, which corresponds to December 13, 1901.

2,147,483,647 → 2038-01-19 03:14:07 UTC (max 32-bit signed)
2,147,483,648 → wraps to negative (underflow)

Systems still vulnerable to Y2038:

  • Embedded systems (routers, IoT devices, car firmware)
  • Legacy databases storing timestamps as INT(10)
  • Old Linux kernels on 32-bit architectures
  • File systems using 32-bit timestamps
  • Older versions of PHP on 32-bit builds

How to check if a system is Y2038-safe:

# Linux — check if time_t is 64-bit
getconf LONG_BIT
# 64 → safe
# 32 → check your kernel and libc version

# PHP — verify integer size
php -r 'echo PHP_INT_SIZE;'
# 8 → safe (64-bit)
# 4 → vulnerable (32-bit)

Modern systems with 64-bit time_t can represent timestamps up to about 292 billion years into the future, making Y2038 a non-issue. Most production servers already run 64-bit operating systems, but embedded and legacy systems remain at risk.

Leap Seconds: The Hidden Complexity

Unix time ignores leap seconds. By definition, each day has exactly 86,400 seconds. But astronomical time (UT1) occasionally requires an extra second — a leap second — to stay aligned with Earth's rotation. When a leap second occurs, Unix time repeats the same second:

2016-12-31 23:59:59 UTC
2016-12-31 23:59:60 UTC  ← leap second (not representable in Unix time)
2017-01-01 00:00:00 UTC

Most applications ignore leap seconds entirely because they occur unpredictably (typically once every 1-3 years) and handling them adds significant complexity. Systems that require precise timekeeping — such as financial trading platforms and astronomical observatories — use TAI (International Atomic Time) or GPS time instead of Unix time.

Common Pitfalls

Pitfall 1: Using the Wrong Unit

// API returns timestamp in seconds
const apiTimestamp = 1782000000;

// ❌ Wrong — new Date() expects milliseconds
const date = new Date(apiTimestamp);

// ✅ Correct
const date = new Date(apiTimestamp * 1000);

Pitfall 2: Storing as INT(10) in MySQL

-- ❌ Wrong — INT(10) overflows at 2.1 billion (2038)
CREATE TABLE events (
    created_at INT(10) NOT NULL
);

-- ✅ Correct — use BIGINT or TIMESTAMP
CREATE TABLE events (
    created_at BIGINT NOT NULL,       -- 64-bit, safe
    created_at2 TIMESTAMP NOT NULL     -- MySQL handles conversion
);

Pitfall 3: Assuming Local Time is the Default

// ❌ Wrong — date() uses the server's default timezone
echo date('Y-m-d H:i:s', $timestamp);

// ✅ Correct — explicitly specify UTC
echo gmdate('Y-m-d H:i:s', $timestamp);
echo date('Y-m-d H:i:s', $timestamp); // if default TZ is set to UTC

Pitfall 4: Integer Overflow in JavaScript

JavaScript numbers are 64-bit floating point but bitwise operations treat them as 32-bit signed integers. This can cause unexpected Y2038-like bugs even on modern browsers.

// JavaScript bitwise operation treats as 32-bit
const timestamp = 2500000000; // beyond 32-bit signed max
const shifted = timestamp << 1; // ❌ overflow!
console.log(shifted); // -1794967296 (wrapped)

Epoch Converter Tool

The Epoch / Unix Timestamp Converter tool on Help2Code provides live current timestamp display in seconds and milliseconds, bidirectional conversion between epoch values and readable dates, and support for both local and UTC timezones. Use it to debug timestamp issues, generate timestamps for testing, or verify API responses. The Timezone Converter tool is also useful for checking how epoch timestamps map to different timezones.

Conclusion

Epoch timestamps are a simple and universal way to represent moments in time, but they come with a few critical caveats: always check whether you are working with seconds or milliseconds, use 64-bit storage to avoid the Y2038 problem, and never assume the default timezone matches your intent. Use the Epoch Converter tool for quick conversions and keep the guidelines above in mind when handling timestamps in production code.


About this article

Learn how Unix epoch timestamps work, why 2038 is a problem, the difference between seconds and milliseconds, and how to avoid common pitfalls.


Related Articles


Related Tools

Help2Code Logo
Menu