Blog
Why Software Doesn't Store Dates — It Stores a Single Number
Unix time collapses every date, timezone, and calendar quirk into one integer counted from 1970. That simplicity is exactly why it works everywhere from log files to distributed systems — and exactly where it quietly breaks.
Open almost any log file, database row, or API response and you'll eventually find a number that looks like 1700000000 sitting where you'd expect a date. That number is a Unix timestamp — the count of seconds (or, increasingly, milliseconds) that have elapsed since midnight UTC on January 1, 1970. It's arguably the single most load-bearing convention in all of computing, and almost nobody thinks about why it exists or what it actually buys you until something about it goes wrong.
A date is not a number, until you decide it is
Calendar dates are a human invention layered on top of physical time, and that layer is messy: months have different lengths, years occasionally get an extra day, and the same moment can fall on two different calendar dates depending on which timezone you're standing in. None of that is a good foundation for a computer to reason about, because "the 3rd" or "next Tuesday" aren't well-ordered, fixed-size units — you can't subtract two calendar dates and get a meaningful answer without first agreeing on a calendar system, a leap-year rule, and a timezone. Unix time sidesteps the entire problem by refusing to represent a date as a date at all. It picks one arbitrary reference instant — the "epoch," January 1, 1970, 00:00:00 UTC — and represents every other instant in history as a single signed integer: the number of seconds before or after that reference point. There's no month-length table to consult, no leap-year exception to apply, and no timezone ambiguity, because the number itself doesn't live in any timezone. It's just an offset from a fixed point on an infinite number line.
That reduction is what makes Unix time so useful as an interchange format. Two systems running on opposite sides of the planet, written in different languages, storing data in different databases, can agree on exactly what instant 1700000000 refers to without ever exchanging a single word about timezones — because the number already encodes an instant, not a local description of one. Converting it into something a person can read — "November 14, 2023, 10:13:20 PM UTC," or the equivalent in whatever timezone a viewer happens to be in — is a display-layer decision that can be deferred to the very last moment, right before a human actually looks at it. Everything upstream of that — storage, comparison, sorting, arithmetic — stays blissfully simple, because it's just integer math.
Why 1970, specifically
The epoch date isn't meaningful in itself — it was chosen somewhat arbitrarily by the designers of Unix in the early 1970s as a convenient "recent enough" reference point for the systems they were building at the time, and it stuck purely through momentum. Once enough software, file formats, and protocols were built assuming that reference point, changing it became effectively impossible — every timestamp ever recorded would need to be reinterpreted against a new baseline, and every system that reads or writes timestamps would need to agree on the change simultaneously. So 1970 remains the anchor not because of anything special about that date, but because switching now would be far more disruptive than any benefit a different anchor could offer. It's a good example of how an arbitrary early decision, once enough is built on top of it, becomes a de facto permanent standard.
Seconds versus milliseconds: the same idea, two competing granularities
The original Unix timestamp counts whole seconds, which was more than precise enough for the systems of the 1970s, but modern applications — especially anything measuring web request latency, animation frames, or high-frequency events — often need finer resolution, so JavaScript's Date.now() and many web APIs report milliseconds since the same 1970 epoch instead. The two conventions look deceptively similar — both are "just a big integer" — which is precisely why mixing them up is such a common bug. A seconds-based timestamp treated as milliseconds lands somewhere in 1970, and a milliseconds-based timestamp treated as seconds lands sometime in the far future, both of which are easy to misread as "an obviously wrong date" without immediately realizing the unit, not the value, is the problem. Most tools that handle raw epoch values, including theUnix Timestamp Converter on this site, guess the unit from the timestamp's magnitude — values below roughly 100 billion are almost certainly seconds (that threshold alone covers every date until the year 5138), and anything larger is almost certainly milliseconds — precisely because this seconds/milliseconds confusion is common enough to be worth guarding against automatically rather than assuming the caller always knows which one they're holding.
The 2038 problem: what happens when the number itself runs out of room
Because so many older systems stored Unix time as a signed 32-bit integer, there's a hard ceiling on how far into the future that representation can count: it overflows at 03:14:07 UTC on January 19, 2038, at which point a 32-bit signed timestamp wraps around to a large negative number — which typically gets interpreted as a date in 1901, not 2038. This is a direct structural echo of the Y2K problem, except the constraint this time comes from binary integer width rather than a two-digit decimal year convention. Most modern systems have already migrated to 64-bit timestamps, which push the overflow date far enough into the future (billions of years) that it's no longer a practical concern, but embedded systems, older databases, and legacy file formats that still rely on 32-bit timestamps remain genuinely exposed — it's a reminder that "we'll deal with it eventually" has a way of becoming "it's now everyone else's emergency" once the eventually arrives.
What this means for reading a raw timestamp
None of this makes epoch time hard to work with — it's precisely because the representation is so minimal that it's trustworthy across languages, databases, and time zones. It just means that turning a raw integer back into something readable requires knowing three things unambiguously: which epoch it's counted from (almost always 1970, but worth confirming for unfamiliar systems), which unit it's counted in (seconds or milliseconds), and which timezone you want it displayed in, since the underlying instant itself has none. Get those three right and the rest — sorting events, computing durations, comparing timestamps across services — is exactly the boring, reliable integer arithmetic Unix time was designed to make possible in the first place.
