Unix Timestamps Explained: What They Are and Why Developers Use Them
Ask a computer what time it is, and deep down it will give you a single integer: the number of seconds that have elapsed since midnight on January 1, 1970, UTC. This is Unix time, and it is the most practical way to store and compare points in time in software.
Why January 1, 1970?
The Unix operating system was being developed in the late 1960s and early 1970s at Bell Labs. When the engineers needed a reference point for measuring time, they chose midnight UTC on January 1, 1970 — a round date that was recent enough to give them useful precision in a 32-bit integer. This moment is called the Unix epoch.
The choice was somewhat arbitrary — it could have been any fixed point — but once established and adopted across Unix systems, it became the de-facto standard for representing time in computing. Today, every major operating system, programming language runtime, and database uses Unix time internally, even if it exposes a friendlier interface to developers.
Why developers prefer epoch timestamps
Human-readable timestamps like 2025-05-30T14:30:00+05:30 are convenient to read but awkward to work with in code:
- Timezone ambiguity — "3:00 PM" means different instants in different timezones. Unix time is always UTC. Two epoch timestamps are directly comparable no matter where the code runs.
- Sortability — a larger integer is always a later point in time. Sorting records by timestamp is a simple integer comparison.
- Arithmetic — calculating "30 days from now" is addition. Calculating "how many seconds between these two events" is subtraction. No calendar libraries needed for basic date math.
- Storage efficiency — a 64-bit integer takes 8 bytes. An ISO 8601 string takes 20–30 bytes. When storing millions of timestamps, this adds up.
- Language-agnostic — pass an epoch integer between a Python service, a Go binary, and a JavaScript frontend and all three know exactly what moment you mean.
Getting the current epoch in common languages
# Bash
date +%s
# Output: 1748534400
# Python
import time
int(time.time())
# Output: 1748534400
# JavaScript (milliseconds — see below!)
Math.floor(Date.now() / 1000)
# Output: 1748534400
# Go
import "time"
time.Now().Unix()
// Output: 1748534400
# PHP
time();
// Output: 1748534400
# PostgreSQL
SELECT EXTRACT(EPOCH FROM NOW())::BIGINT;
-- Output: 1748534400The milliseconds vs seconds gotcha
This is the most common source of Unix timestamp bugs. JavaScript's Date.now() returns milliseconds since the epoch, not seconds. Most other languages and systems use seconds.
// JavaScript
Date.now() // 1748534400000 (milliseconds)
Date.now() / 1000 // 1748534400.000 (seconds, as float)
Math.floor(Date.now() / 1000) // 1748534400 (seconds, as integer)
// Common bug: passing a JS timestamp to a seconds-based API
fetch('/api/event', {
body: JSON.stringify({ timestamp: Date.now() }) // WRONG: 13-digit number
// Should be: timestamp: Math.floor(Date.now() / 1000) // 10-digit number
})A quick sanity check: a Unix timestamp in seconds is currently a 10-digit number (around 1.7 billion). If you see a 13-digit timestamp, it's in milliseconds. If you see a 10-digit one, it's in seconds.
The year 2038 problem
Many older systems stored Unix timestamps as a 32-bit signed integer, which can hold values from −2,147,483,648 to 2,147,483,647. The maximum value of a 32-bit signed timestamp corresponds to January 19, 2038, at 03:14:07 UTC. After that moment, a 32-bit counter would roll over to a large negative number — interpreted as a date in 1901.
Modern systems use 64-bit integers for timestamps. A 64-bit signed Unix timestamp can represent dates up to the year 292,277,026,596 — comfortably beyond any practical concern. The 2038 problem is a real risk only in legacy embedded systems, older 32-bit operating systems, and databases with timestamp columns defined as 32-bit integers.
If you maintain an application that stores timestamps in a relational database, verify that your timestamp columns are defined as BIGINT or the database's native 64-bit timestamp type. MySQL's TIMESTAMP type, for example, has a known 2038 limitation; use DATETIME instead.