Snappy ToolsUnix timestamps are everywhere in software — database records, API responses, JWT expiry, log files,...
Unix timestamps are everywhere in software — database records, API responses, JWT expiry, log files, file metadata. Here's a complete reference for working with them across languages and environments.
A Unix timestamp is the number of seconds elapsed since the Unix epoch: January 1, 1970, 00:00:00 UTC.
0 → 1970-01-01 00:00:00 UTC
1000000000 → 2001-09-09 01:46:40 UTC
1746144000 → 2025-05-02 00:00:00 UTC
Timestamps store a single integer instead of separate year, month, day, hour, minute, second fields — simpler to store, sort, and compare.
To convert between Unix timestamps and human-readable dates, the Unix Timestamp Converter converts in both directions and handles millisecond timestamps too.
JavaScript (and many other environments) uses milliseconds since the epoch, not seconds:
Date.now() // 1746144000000 (milliseconds)
APIs vary — some return seconds, some milliseconds. A quick way to tell: timestamps in milliseconds are roughly 1000× larger than those in seconds. In 2025:
When in doubt, check the magnitude.
// JavaScript
Date.now() // milliseconds
Math.floor(Date.now() / 1000) // seconds
# Python
import time
int(time.time()) # seconds
int(time.time() * 1000) # milliseconds
// Go
import "time"
time.Now().Unix() // seconds
time.Now().UnixMilli() // milliseconds
# Shell
date +%s # seconds
date +%s%3N # milliseconds
-- PostgreSQL
EXTRACT(EPOCH FROM NOW())::int -- seconds
// JavaScript
const ts = 1746144000; // seconds
const date = new Date(ts * 1000); // Date constructor takes milliseconds
date.toISOString() // "2025-05-02T00:00:00.000Z"
date.toLocaleDateString() // locale-specific format
# Python
from datetime import datetime, timezone
ts = 1746144000
dt = datetime.fromtimestamp(ts, tz=timezone.utc)
dt.isoformat() # '2025-05-02T00:00:00+00:00'
Timestamps are always UTC. The same timestamp shows different times in different timezones — correct behavior, but easy to misread.
const ts = 1746144000;
const d = new Date(ts * 1000);
d.toISOString() // "2025-05-02T00:00:00.000Z" — always UTC
d.toLocaleDateString() // "5/1/2025" if you're in US/Pacific (UTC-7) — 11pm the day before!
The most common timestamp bug: passing seconds where milliseconds are expected.
// Wrong: passing seconds to Date constructor
new Date(1746144000) // 1970-01-21 — the timestamp is tiny in millisecond space
// Right:
new Date(1746144000 * 1000) // 2025-05-02
new Date(1746144000000) // also 2025-05-02
Unix timestamps stored as 32-bit signed integers overflow on January 19, 2038 at 03:14:07 UTC — the Y2K38 problem. 2³¹ - 1 = 2,147,483,647 seconds.
Modern systems use 64-bit integers, which won't overflow for billions of years. But legacy 32-bit databases and embedded systems still need updating.
// Add 7 days
const now = Math.floor(Date.now() / 1000);
const oneWeekLater = now + (7 * 24 * 60 * 60);
// How many days ago?
function daysAgo(ts) {
return Math.floor((Math.floor(Date.now() / 1000) - ts) / 86400);
}
// Is this timestamp in the past?
function isExpired(ts) {
return ts < Math.floor(Date.now() / 1000);
}
// JWT expiry check (exp field is Unix seconds)
function isJwtExpired(exp) {
return exp < Math.floor(Date.now() / 1000);
}
Use Intl.DateTimeFormat for locale-aware formatting:
const ts = 1746144000;
const d = new Date(ts * 1000);
// Relative time ("3 days ago")
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
const diffDays = Math.floor((Date.now() / 1000 - ts) / 86400);
rtf.format(-diffDays, 'day'); // "3 days ago"
// Absolute time with explicit timezone
new Intl.DateTimeFormat('en-US', {
timeZone: 'America/New_York',
year: 'numeric', month: 'short', day: 'numeric',
hour: '2-digit', minute: '2-digit'
}).format(d); // "May 1, 2025 at 08:00 PM"
Use 64-bit integer columns for Unix timestamps:
BIGINT or native TIMESTAMPTZ (preferred — stores UTC, converts on read)BIGINT UNSIGNED or DATETIME(3) for millisecond precisionINTEGER (64-bit internally)Date type (stores as UTC milliseconds)TIMESTAMPTZ in PostgreSQL is generally the right choice for application timestamps — it handles timezone conversion automatically. Use raw BIGINT timestamps only when interoperating with systems that exchange raw numbers.
Unix timestamps are simple in principle — one integer representing a moment in UTC — but the seconds/milliseconds distinction and timezone handling cause most of the practical bugs. Get those two right and timestamp work becomes straightforward.