Epoch Time Explained — What Is Unix Epoch and Why Does It Start January 1, 1970?
Unix epoch time counts seconds from January 1, 1970 00:00:00 UTC. Learn why 1970 was chosen, how to work with epoch time in JavaScript and Python, the Year 2038 problem, and...
Unix epoch time is the number of seconds elapsed since January 1, 1970, 00:00:00 Coordinated Universal Time (UTC). It’s the universal language for timestamps in computer systems.
Convert epoch timestamps instantly with the Timestamp Converter.
Why January 1, 1970?
The Unix operating system was developed at Bell Labs in the late 1960s. When the developers needed a reference point for timestamps, they chose a date “in the recent past” — recent enough to not require large numbers for common dates.
The date went through several iterations:
- January 1, 1971 (first version)
- January 1, 1970 (settled on around 1973 when Unix was being more formally defined)
It’s arbitrary, but once chosen, every Unix-like system adopted it. Today it’s the universal reference point for computing time.
What the epoch number looks like
January 1, 1970 00:00:00 UTC = 0
January 1, 2000 00:00:00 UTC = 946684800
January 1, 2026 00:00:00 UTC = 1767225600
May 12, 2026 14:30:00 UTC ≈ 1747063800
The number grows by 1 every second. By 2026, we’re around 1.7 billion seconds past the epoch.
Seconds vs milliseconds
Different systems use different granularities:
// Seconds (Unix standard):
Math.floor(Date.now() / 1000) // ~1747063800
// Milliseconds (JavaScript standard):
Date.now() // ~1747063800000
// Common confusion: JavaScript always uses milliseconds
new Date(1747063800) // 1970-01-21... (treating as ms, not seconds!)
new Date(1747063800 * 1000) // 2026-05-12... (correct: multiply by 1000)
new Date(1747063800000) // 2026-05-12... (correct: already ms)
Rule of thumb: If the number has 10 digits, it’s seconds. If it has 13 digits, it’s milliseconds.
Getting epoch time
// JavaScript:
const seconds = Math.floor(Date.now() / 1000); // 10-digit number
const milliseconds = Date.now(); // 13-digit number
const performance = performance.now(); // High-precision ms since page load
import time
from datetime import datetime, timezone
# Seconds (float):
time.time() # 1747063800.123456
# Seconds (integer):
int(time.time()) # 1747063800
# Milliseconds:
int(time.time() * 1000) # 1747063800123
# Using datetime:
datetime.now(timezone.utc).timestamp() # 1747063800.123456
# Shell:
date +%s # seconds: 1747063800
date +%s%N # nanoseconds: 1747063800123456789
Converting epoch to human-readable
// Milliseconds to Date:
new Date(1747063800000).toISOString();
// "2026-05-12T14:30:00.000Z"
// Seconds to Date:
new Date(1747063800 * 1000).toISOString();
// "2026-05-12T14:30:00.000Z"
from datetime import datetime, timezone
# Seconds to datetime:
datetime.fromtimestamp(1747063800, tz=timezone.utc)
# datetime(2026, 5, 12, 14, 30, 0, tzinfo=timezone.utc)
# Format:
datetime.fromtimestamp(1747063800, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')
# "2026-05-12 14:30:00 UTC"
The Year 2038 Problem
32-bit signed integers max out at 2,147,483,647 — which corresponds to January 19, 2038, 03:14:07 UTC.
After that point, a signed 32-bit integer wraps to a large negative number, causing timestamp overflow.
// C: 32-bit time_t overflow
time_t t = 2147483647; // 2038-01-19 03:14:07 UTC
t++; // -2147483648 = December 13, 1901 (!)
Solutions:
- Modern 64-bit systems use 64-bit
time_t— can represent dates up to year 292 billion - MySQL’s
TIMESTAMPtype (32-bit) has a 2038 problem;DATETIME(64-bit) does not - Most modern software already uses 64-bit timestamps
JavaScript is safe: JavaScript uses 64-bit floats for Date, handling dates up to year 275,760.
Negative epoch values
// Dates before January 1, 1970 have negative epoch values:
new Date(-1000).toISOString(); // "1969-12-31T23:59:59.000Z"
new Date(-86400000).toISOString(); // "1969-12-31T00:00:00.000Z"
datetime.fromtimestamp(-1000, tz=timezone.utc)
# datetime(1969, 12, 31, 23, 43, 20, tzinfo=timezone.utc)
Epoch time in databases
-- PostgreSQL: store as BIGINT (milliseconds) or TIMESTAMPTZ
-- TIMESTAMPTZ is stored as UTC microseconds since epoch internally
-- MySQL: TIMESTAMP (32-bit, expires 2038) vs DATETIME (64-bit, recommended)
-- Use BIGINT UNSIGNED for millisecond epoch if you need portability
-- SQLite: store as INTEGER (seconds) for simplicity:
CREATE TABLE events (
id INTEGER PRIMARY KEY,
created_at INTEGER NOT NULL -- Unix seconds
);
Related tools
- Timestamp Converter — convert epoch timestamps
- JSON Formatter — inspect API responses with timestamps
- Hash Generator — generate time-based token identifiers
Related posts
- Unix Timestamps and Timezones: What Can Go Wrong — Unix timestamps are always UTC — but displaying, parsing, and storing them is wh…
- Date to Unix Timestamp — Convert Any Date to Unix Time — Converting a date to a Unix timestamp gives you the seconds since January 1, 197…
- ISO 8601 Date Format — The Standard for Dates in APIs and Databases — ISO 8601 is the international standard for representing dates and times. Learn t…
- Unix Timestamp — What Epoch Time Is and How to Convert It — A Unix timestamp is seconds since January 1, 1970 UTC. It's the standard time re…
Related tool
Convert Unix timestamps, epoch seconds/milliseconds, and ISO 8601 dates.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.