Unix Timestamps Explained: Seconds, Milliseconds and the Year 2038
How Unix time works, why some systems use seconds and others use milliseconds, the Year 2038 problem, and how to convert between epoch and human dates without going mad.
A Unix timestamp is just a count of seconds since 1 January 1970, UTC. That's it. The reason this simple idea matters is that it's the universal way to represent a moment in time across every programming language, database, and operating system. Dates and time zones are a mess; Unix timestamps are a single integer.
Convert now: the Timestamp Converter converts Unix epoch to/from human-readable dates with a live current-epoch ticker. Auto-detects seconds vs milliseconds.
How Unix time works
Pick any moment in time. Count the number of seconds since 00:00:00 UTC on 1 January 1970. That number is the Unix timestamp.
- 1 Jan 1970 00:00:00 UTC = 0
- 1 Jan 2026 00:00:00 UTC = 1767225600
- 2026-05-26 14:30:00 UTC = 1779036600 (roughly)
The reference moment is called the Unix epoch. The choice of date is arbitrary — Unix was being developed at Bell Labs in the early 70s and they needed a starting point.
Seconds vs milliseconds
Different systems use different precision:
- Seconds since epoch: the original. Used by Unix tools (
date +%s), PostgreSQLextract(epoch from ...), RFC 3339 dates without milliseconds. - Milliseconds since epoch: 1000× bigger numbers. Used by JavaScript's
Date.now(), Java'sSystem.currentTimeMillis(), many modern APIs. - Microseconds and nanoseconds appear in high-precision contexts:
process.hrtime()in Node, some database functions, performance timing.
The fast way to detect which: count digits. Current era seconds is 10 digits; milliseconds is 13. Past 11/20/2286, seconds becomes 11 digits — but for the next ~200 years, the rule holds.
Why use Unix time instead of dates?
- No time zone ambiguity. "2026-05-26 14:30" requires you to know if that's UTC, local, or whose local. A Unix timestamp is unambiguously UTC by definition.
- Compact storage. One 4 or 8-byte integer vs a 24-character string.
- Fast arithmetic. Subtracting two timestamps gives you a duration in seconds. No date math.
- Sortable. Older means smaller. Newer means bigger. No locale-aware sorting.
- Universal. Every programming language understands integers.
The Year 2038 problem
32-bit signed integers can store values from -2,147,483,648 to 2,147,483,647. The maximum positive value in seconds since epoch is reached at 03:14:07 UTC on 19 January 2038. After that, 32-bit Unix timestamps overflow into negative numbers — interpreting "now" as some moment in 1901.
Modern systems use 64-bit integers which extend the range to ~292 billion years either side of 1970. The Year 2038 problem affects:
- Legacy embedded systems (industrial controllers, old network equipment) that may still be running 32-bit code in 2038.
- Old file formats that store dates as 32-bit timestamps and would need migration.
- Legacy database schemas that haven't been updated.
Most modern OS, languages and databases moved to 64-bit timestamps years ago. The 2038 problem is real but in a manageable place.
Converting in your language
// JavaScript
const now = Math.floor(Date.now() / 1000) // seconds
const ms = Date.now() // milliseconds
const date = new Date(timestamp * 1000) // back to Date
// Python
import time
now = int(time.time()) // seconds
from datetime import datetime
date = datetime.fromtimestamp(timestamp) // back
// SQL (PostgreSQL)
SELECT extract(epoch from now()); -- current epoch
SELECT to_timestamp(1767225600); -- back to date
// Bash
date +%s // current epoch
date -d @1767225600 // back to human
// Go
import "time"
ts := time.Now().Unix() // seconds
t := time.Unix(ts, 0) // backISO 8601 — the readable companion
Unix timestamps are great for storage and computation but unreadable for humans. ISO 8601 is the standard human-readable format that's also machine-parseable:
2026-05-26T14:30:00Z — UTC
2026-05-26T14:30:00+05:30 — IST (India)
2026-05-26T14:30:00-04:00 — EDT (NYC summer)Most APIs in 2026 prefer ISO 8601 over Unix timestamps in JSON because it's both human-readable AND machine-parseable. Use Unix timestamps for internal storage; convert to ISO 8601 for API boundaries.
Common pitfalls
- Mixing seconds and milliseconds. Most "off by 1000x" date bugs are this. Always know which one your input is.
- Time zone confusion. Unix timestamps are always UTC. If you "convert" to local time and store the local timestamp, you've lost the original. Store UTC, display local.
- JavaScript Date trap.
new Date("2026-05-26")parses as midnight UTC.new Date("2026-05-26T14:30")with no timezone is local time. The first parses as the second on different machines depending on time zone. - Leap seconds. Unix time ignores leap seconds. Two timestamps that span a leap second appear to have a 1-second gap when there were actually 2 seconds. Almost never matters unless you're building astronomy or banking software.
When to use what
- Database timestamp columns: use the native type (TIMESTAMP, TIMESTAMPTZ in Postgres). Don't store Unix integers — you lose query expressiveness.
- Inside your app: Unix timestamp seconds for compactness and speed.
- API request/response bodies: ISO 8601 string. Both humans and machines read it.
- Filenames: Unix epoch or ISO 8601 — both are sortable. ISO is more readable.
- Cache keys: Unix epoch is fine.
The 30-second skill
Be able to read 1767225600 and know it's roughly "Jan 2026". The numeric pattern in 2020s is "17 followed by 8 more digits". Memorise that and you can sanity-check timestamps in logs without reaching for a converter.
Convert any timestamp: Timestamp Converter — paste epoch, see human date. Pick a date, get epoch. Live current ticker. Local timezone and UTC both shown.