Unix Timestamps Explained: Epoch Time, Time Zones, and the 2038 Problem
· by Andergrove Software
A Unix timestamp is just a count of seconds since 1970-01-01 00:00:00 UTC,
the moment programmers call "the epoch." A value like 1751155200 is not random;
it is one specific instant, the same instant everywhere on Earth, because it is measured in
UTC with no time zone attached. That simplicity is why timestamps are everywhere in logs,
databases and APIs, and also where the confusion starts.
Here is what the number means, the seconds-versus-milliseconds trap, why you should store UTC and format only on display, and the Year 2038 problem waiting in older systems. You can convert any timestamp both ways in the timestamp converter as you read.
What the number counts
The epoch is 1970-01-01T00:00:00Z. A Unix timestamp is the number of seconds
elapsed since then (ignoring leap seconds). Because it is anchored to UTC, the same timestamp
refers to the same instant no matter where the reader sits: a server in Sydney and a browser
in London agree on 1751155200, then each formats it into local time for display.
Store the instant, present the local time.
Seconds vs. milliseconds: the off-by-1000 bug
The single most common timestamp bug: Unix time is in seconds, but many
languages report milliseconds. JavaScript's Date.now() returns
milliseconds; most Unix tooling, databases and APIs use seconds. Mix them up and you land in
1970 or somewhere in the year 56000.
A quick sniff test: a seconds timestamp for "now" has 10 digits (until the year 2286); a milliseconds one has 13. If a date comes out wildly wrong, check whether you need to multiply or divide by 1000.
Time zones and daylight saving
A Unix timestamp has no time zone: it is always UTC. Time zones and daylight
saving only enter the picture when you format a timestamp for a human. The rule that
saves the most pain is simple: store and compute in UTC, and convert to local time
only at the edges, on display. Storing local times invites ambiguity (which
01:30 during the autumn rollback?) and breaks arithmetic across DST boundaries.
The Year 2038 problem
Many older systems store the timestamp in a signed 32-bit integer. The
largest value it can hold is 2,147,483,647 seconds, reached at 03:14:07 UTC on 19
January 2038. One second later it overflows to a negative number and wraps back to
December 1901. It is the 21st-century echo of Y2K, affecting embedded devices, old file
formats, and legacy C code that still uses a 32-bit time_t.
The fix is already widespread: 64-bit timestamps, which push the overflow roughly 292 billion years out. Modern operating systems and languages use 64-bit time; the remaining risk lives in embedded and legacy systems that are hard to update.
Get epoch time anywhere
JavaScript Math.floor(Date.now() / 1000) // seconds (Date.now() is ms)
Python import time; int(time.time())
SQL (Postgres) SELECT extract(epoch from now())::bigint;
Shell date +%s
Convert it
Paste any epoch value, seconds or milliseconds, into the Andergrove Timestamp Converter to see the human date in UTC and your local zone, or go the other way from a date to a timestamp. It runs entirely in your browser. Counting down to a specific date instead? The age & countdown calculator handles that. Timestamps even hide inside modern identifiers: a UUIDv7 is timestamp-prefixed, so you can generate a sortable, time-ordered ID with the UUID generator.