At some point you open a database table and find a column full of numbers like 1711584000. No column comment, no documentation. You try to guess the format — too big to be a year, too small to be milliseconds. You paste it into a search and land on a Unix timestamp converter. "Oh. It's a date. January something, 2024." That's usually the moment the concept clicks.
Unix timestamps are one of those foundational ideas that seem trivial once you understand them, but cause genuine confusion before you do. Let me walk through what they actually are, why they're designed the way they are, and the handful of pitfalls that bite everyone at least once.
What a Unix timestamp is
A Unix timestamp is a single integer: the number of seconds elapsed since midnight on January 1, 1970, UTC. That reference point is called the Unix epoch. Everything before it is a negative number; everything after is positive.
0→ January 1, 1970, 00:00:00 UTC1000000000→ September 9, 2001, 01:46:40 UTC (people threw parties for this one)1711584000→ March 27, 2024, 16:00:00 UTC2147483647→ January 19, 2038, 03:14:07 UTC (more on this later)
Why 1970? The Unix operating system was being developed in the late '60s and early '70s, and the developers needed a starting point. January 1, 1970 was a convenient recent date. No deep reason. The choice was slightly arbitrary, and has been mildly haunting the industry ever since.
Why this format persists
The elegance of a Unix timestamp is that it's just a number. No timezone embedded in it, no locale formatting, no calendar system assumptions. When two systems exchange a timestamp, they're exchanging a single unambiguous integer that means the same thing in Tokyo and Toronto.
Compare this to storing "March 27, 2024 4:00 PM". What timezone? What locale format? Is that 4pm local server time, or user time? These questions don't exist with a timestamp. You store the integer, and when you need to show it to a user, you convert it to their local timezone in the UI layer.
Duration math is also trivially simple: end - start gives you elapsed seconds. No month-length logic, no leap year handling, no timezone offset arithmetic. Two timestamps, one subtraction.
Seconds vs milliseconds — the most common gotcha
JavaScript's Date.now() returns milliseconds, not seconds. So does System.currentTimeMillis() in Java. Many modern APIs use milliseconds for higher precision. But the traditional Unix standard is seconds, and a lot of systems, databases, and older APIs use seconds.
The problem: 1711584000 (seconds) and 1711584000000 (milliseconds) are both valid-looking integers, but they refer to completely different things. The second one is roughly the year 56,000.
When you're integrating with an API and the dates come back looking wildly wrong — a "created_at" field showing 55,000 AD — that's almost certainly a seconds/milliseconds mismatch. Multiply or divide by 1000 and see if the dates make sense.
// Current time in seconds
const nowSeconds = Math.floor(Date.now() / 1000);
// Convert a seconds-based timestamp to a JS Date
const date = new Date(1711584000 * 1000); // must multiply by 1000
console.log(date.toISOString()); // "2024-03-27T16:00:00.000Z"
// If you already have milliseconds
const date2 = new Date(1711584000000); // no multiplication needed
from datetime import datetime, timezone
import time
# Current seconds
now = int(time.time())
# Parse a timestamp (seconds)
dt = datetime.fromtimestamp(1711584000, tz=timezone.utc)
print(dt.isoformat()) # 2024-03-27T16:00:00+00:00
A quick sanity check: the current time in seconds is somewhere around 1.7 billion. If your timestamp is 1.7 trillion, it's in milliseconds.
The 2038 problem
32-bit signed integers max out at 2,147,483,647. In Unix timestamp terms, that's January 19, 2038, at 03:14:07 UTC. After that moment, a 32-bit timestamp overflows and wraps to a large negative number, which typically gets interpreted as a date in 1901.
This is the Y2K of the 2030s. Most major systems have already migrated to 64-bit timestamps, which can represent dates roughly 292 billion years into the future, so the problem is largely solved at the OS and language level. But embedded systems, some IoT devices, old C libraries, and legacy databases that still use INT(11) for timestamp columns could genuinely have issues. If you're writing code that involves timestamps and the data will still exist in 2038, use 64-bit integers or a proper datetime type.
Timezone handling in practice
The most important thing to internalize: a Unix timestamp has no timezone. It's always UTC. When you call datetime.fromtimestamp() in Python without specifying tz=timezone.utc, it silently uses your local system timezone. On your laptop in Tokyo that's one time, on a UTC server it's another.
This is the source of a whole class of bugs where "dates are off by 9 hours in production but fine locally." Always be explicit about timezone when converting a timestamp to a human-readable date. Convert to the user's local timezone only at the display layer.
SQL databases vary here. MySQL's FROM_UNIXTIME() uses the server's session timezone. PostgreSQL's to_timestamp() returns a timestamptz in UTC. Always check what your database returns and add explicit timezone handling in your application.
When to use them (and when not to)
Unix timestamps are great for: logging events, comparing durations, storing "when did this happen" data in APIs and databases, sorting records chronologically, and any scenario where two different systems need to agree on a moment in time.
They're less suited for: representing a "date" without a time (like someone's birthday), representing recurring events with timezone-specific meaning (like "every Monday at 9am in New York"), or any domain where humans will need to read the raw values without a converter.
For date-only values, ISO 8601 date strings (2024-03-27) are usually cleaner. For recurring schedules, you typically store the rule plus a base timezone separately.
Need to turn a Unix timestamp into a readable date, or find the timestamp for a specific moment in time? Use the free Timestamp Converter — it handles both seconds and milliseconds and shows results in your local timezone.