Development

Epoch Time Guide: Epochs, Units & Precision

By AZ Utils Editorial · · 11 min read

Epoch Time Guide: Epochs, Units & Precision

"Epoch time" sounds like one specific thing, but it is really a family of conventions — and the differences between them are behind a surprising number of date bugs when data crosses between systems. This guide is a thorough tour of epoch time: what an epoch is, the famous Unix epoch, the other epochs you will meet, the precision levels from seconds to nanoseconds, and how to store and convert epoch time correctly.

It is written for developers and engineers who store and move timestamps, students learning how computers anchor time, and anyone who has been bitten by a date that was decades off.

What Is an Epoch?

In timekeeping, an epoch is simply a chosen reference point — a "time zero" — from which moments are counted. Once you fix an epoch and a unit (seconds, milliseconds, and so on), any instant can be named as a single number: the count of those units elapsed since the epoch. The number is meaningless without knowing both the epoch and the unit, which is precisely where confusion creeps in when systems disagree about either.

The most famous epoch in computing is the Unix epoch: 00:00:00 UTC on 1 January 1970. "Epoch time" and "Unix time" are often used as synonyms because the Unix convention is so dominant. But it is far from the only epoch in use, and treating a number from one system as if it used a different epoch produces dates that are wrong by years or even centuries.

In short: An epoch is a reference "time zero" from which time is counted. The Unix epoch (1 Jan 1970 UTC, counted in seconds) is the most common, but systems like NTP, GPS, Windows and spreadsheets use different epochs and units — so always know both before interpreting a timestamp.

The Other Epochs You Will Meet

Different platforms picked different reference points for historical reasons. The ones worth recognising:

SystemEpochUnit
Unix / POSIX1 Jan 1970 UTCSeconds
JavaScript / Java1 Jan 1970 UTCMilliseconds
NTP (network time)1 Jan 1900 UTCSeconds
GPS6 Jan 1980 UTCSeconds (no leap seconds)
Windows FILETIME1 Jan 1601 UTC100-nanosecond ticks
.NET DateTime ticks1 Jan 0001100-nanosecond ticks
Apple / Cocoa1 Jan 2001 UTCSeconds
Excel / Sheets~1 Jan 1900Days

The practical lesson is that a "timestamp" copied from a Windows API, an NTP packet, a GPS receiver or a spreadsheet is not a Unix timestamp. To convert it you must shift from its epoch to the Unix epoch and rescale its unit. Forgetting this is why a value can decode to 1601, 1900 or 2001 instead of the date you expected.

Why So Many Epochs Exist

It is reasonable to ask why the computing world never settled on a single epoch, and the answer is that each was a sensible local choice that later had to coexist with the others. When the designers of a system needed a reference point for time, they picked one that suited their context. Unix chose 1970 because it was a recent, convenient round date during the system's early development. Windows used 1601 because it aligns neatly with the proleptic Gregorian calendar's 400-year cycle, simplifying certain calendar calculations. NTP chose 1900, GPS chose its own system start in 1980, and spreadsheet software inherited a 1900-era epoch from an earlier product for compatibility. None of these were wrong; they were each reasonable in isolation.

The friction only appears at the boundaries, when data crosses from one system to another and a number anchored to one epoch is read by software assuming a different one. There was never a moment when the industry could have agreed on a single epoch, because these systems evolved independently over decades and each had real compatibility reasons to keep its convention. The result is the patchwork we live with: a stable, well-understood set of epochs that interoperate fine as long as you convert between them deliberately. Understanding why the diversity exists makes it less surprising and easier to handle — you stop expecting every timestamp to be a Unix timestamp and start asking, as a matter of routine, which epoch and unit a given number actually uses.

How to Reason About an Unknown Timestamp

Sooner or later you will be handed a bare number and asked what time it represents, with no documentation of its epoch or unit. There is a reliable way to reason it out. Start with the magnitude, which narrows the unit: for the current era, ten digits suggests seconds, thirteen suggests milliseconds, and larger values suggest microseconds or nanoseconds. Then consider the source system, because that hints at the epoch — a value from a Windows API is likely FILETIME counted from 1601, a value from network-timing code may be NTP from 1900, and a value from a spreadsheet is probably a day count from 1900. With a hypothesis for both unit and epoch, you decode the number and check whether the resulting date is plausible: does it fall in a sensible range for the data, neither stuck at an epoch boundary nor flung into the far future or distant past?

If the decoded date looks wrong, the error usually points to which assumption to revise. A date thousands of years out suggests the unit is wrong; a date centuries off suggests the epoch is wrong. Iterating through these possibilities — adjusting the unit, then the epoch — converges quickly on the correct interpretation. This detective work is far easier when you have internalised the common epochs and the digit-count heuristic, which is why they are worth committing to memory. A timestamp is only mysterious when you lack those reference points; with them, even an undocumented number gives up its meaning in a minute or two.

Precision: Seconds to Nanoseconds

Beyond the epoch, systems differ in how finely they slice time. The common precision levels are:

  • Seconds — classic Unix time; a 10-digit number for the current era.
  • Milliseconds (10−3 s) — JavaScript and Java; a 13-digit number.
  • Microseconds (10−6 s) — databases and high-resolution logs; 16 digits.
  • Nanoseconds (10−9 s) — Go's time.UnixNano, high-precision systems; 19 digits.

Each step multiplies the number by a thousand, which means the digit count is a quick clue to the unit. A value around 1.7 billion is seconds; 1.7 trillion is milliseconds; 1.7 quadrillion is microseconds; 1.7 quintillion is nanoseconds. When you ingest a timestamp of unknown origin, the order of magnitude tells you both roughly when it is and which unit it uses.

How Systems Store Epoch Time

Languages and databases expose epoch time in their own ways, and knowing the unit each uses avoids the factor-of-1000 trap:

JavaScript:  Date.now()              // milliseconds
Python:      time.time()             // seconds (float)
Go:          time.Now().Unix()       // seconds
             time.Now().UnixNano()   // nanoseconds
Java:        System.currentTimeMillis() // milliseconds
PHP:         time()                  // seconds
PostgreSQL:  EXTRACT(EPOCH FROM now())  // seconds (numeric)

For storage, the durable advice is to use a 64-bit integer (or the database's native timestamp type) and to be explicit about the unit in your schema and variable names. A column called created_at_ms or expires_at_seconds documents its own unit and prevents an entire category of bugs.

The Year 2038 Problem

The best-known epoch hazard is the Year 2038 problem. A signed 32-bit integer can count seconds only up to 2,147,483,647, which is reached at 03:14:07 UTC on 19 January 2038. Beyond that, a 32-bit counter overflows to a negative value and software misreads the date as 1901. The remedy, already standard on modern platforms, is to store time in 64-bit integers, which extends the range far beyond any practical concern. When designing new systems, never store seconds-based time in a 32-bit field. It is worth noting that the 2038 limit applies specifically to signed 32-bit seconds — systems using 64-bit integers, or millisecond and finer units stored in 64-bit fields, have ranges so vast that overflow is a non-issue for any practical purpose. The problem is therefore not inherent to epoch time itself but to an undersized container for it, and choosing a 64-bit type makes it disappear entirely. The lingering risk lives in legacy code, embedded firmware and old data formats that still assume 32 bits, which is why reviewing how time is stored is a worthwhile part of modernising any older system.

Converting Between Epochs

Converting a non-Unix epoch value to a Unix timestamp is a two-step shift: rescale the unit to seconds, then adjust for the difference between the two epochs. For example, NTP time counts seconds from 1900, which is 2,208,988,800 seconds before the Unix epoch, so subtracting that constant converts NTP seconds to Unix seconds. Windows FILETIME counts 100-nanosecond ticks from 1601, so you divide by 10,000,000 to get seconds and subtract the 1601-to-1970 offset. The arithmetic is simple once you know each system's epoch and unit — and dangerous if you assume every number is a Unix timestamp. When in doubt, decode the value, sanity-check the resulting date, and confirm it lands where you expect.

Try Our Free Timestamp Converter

To check what a Unix timestamp represents — or to convert a date back to one — use our Timestamp Converter.

  • ✅ Unix timestamp ↔ human date
  • ✅ Handles seconds and milliseconds
  • ✅ Instant and private in your browser

👉 Convert a timestamp now →

Epoch Time in Distributed Systems

Epoch time earns its keep most visibly in distributed systems, where many independent machines must agree on the order and timing of events. Because a Unix timestamp is an absolute, time-zone-independent number, it gives every node a common language for time: a server in one data centre can stamp an event, another node thousands of miles away can compare it against its own events, and the ordering is meaningful without anyone negotiating time zones or calendar conventions. This is why logs, message queues, distributed databases and event-streaming platforms lean so heavily on epoch timestamps — they are the lowest-friction way to make time comparable across a fleet of machines.

That said, distributed time has its own subtleties that epoch encoding alone does not solve. Different machines' clocks drift apart unless disciplined by a protocol like NTP, so two timestamps from two servers are only as trustworthy as their clock synchronisation. Systems that need a strict, reliable ordering of events sometimes layer logical clocks or hybrid logical clocks on top of physical epoch time to handle the cases where wall-clock timestamps alone are ambiguous. The epoch timestamp remains the foundation — the shared, absolute reference — but in serious distributed systems it is one ingredient in a more careful approach to time rather than the whole answer. Recognising both its power and its limits keeps you from either underusing it or trusting it more than clock synchronisation warrants.

Choosing How to Store Time

When you design a schema or data model, the choice of how to represent time deserves a moment's thought rather than a reflex. The most robust default for most applications is a 64-bit integer Unix timestamp, or the database's native timestamp-with-time-zone type, both of which store an unambiguous absolute instant compactly and sort correctly. Avoid storing time as a formatted string for anything you will compute with, because strings invite parsing ambiguity and sort incorrectly unless they happen to be in a strict format like ISO 8601. Decide your unit deliberately — seconds is plenty for most records, milliseconds when you need to order closely spaced events — and document it in the column name so nobody downstream has to guess. With a 64-bit integer, a clear unit, and UTC as the reference, your stored time will remain correct, comparable and trouble-free for as long as the data lives.

Common Mistakes

  1. Assuming every timestamp uses the Unix epoch. Windows, NTP, GPS, Apple and spreadsheets use different reference points.
  2. Ignoring the unit. Seconds, milliseconds, microseconds and nanoseconds differ by factors of a thousand.
  3. Storing seconds in a 32-bit field. This invites the 2038 overflow.
  4. Mixing epochs in arithmetic. Subtracting an NTP value from a Unix value without adjusting epochs gives nonsense.
  5. Leaving the unit undocumented. Unlabelled timestamp columns breed factor-of-1000 bugs.

Best Practices

  • Always know the epoch and the unit before interpreting any timestamp.
  • Standardise on the Unix epoch in UTC internally, converting other epochs at the boundary.
  • Use 64-bit storage and document the unit in names and schemas.
  • Use the digit count as a quick unit check (~10 = seconds, ~13 = ms, and so on).
  • Sanity-check converted dates against the era you expect.

Frequently Asked Questions

What is epoch time?

Epoch time is a way of representing an instant as the number of units (often seconds) elapsed since a fixed reference point called the epoch. The most common is the Unix epoch, 1 January 1970 UTC.

Is epoch time the same as Unix time?

"Epoch time" usually means Unix time because the Unix epoch is so dominant, but other systems use different epochs — such as 1900 for NTP, 1980 for GPS and 1601 for Windows FILETIME — so the terms are not strictly identical.

What are the different epoch reference points?

Common epochs include Unix/JavaScript (1970), NTP (1900), GPS (1980), Windows FILETIME (1601), .NET ticks (year 1), Apple/Cocoa (2001) and spreadsheets (around 1900), each with its own unit.

How do I tell which unit a timestamp uses?

Use the digit count for the current era: about 10 digits is seconds, 13 is milliseconds, 16 is microseconds and 19 is nanoseconds, each a factor of a thousand apart.

How do I convert a non-Unix epoch to Unix time?

Rescale the value to seconds, then add or subtract the offset between the two epochs. For example, subtract 2,208,988,800 to convert NTP seconds (from 1900) to Unix seconds (from 1970).

Why does my timestamp show the year 1601 or 1900?

Because it uses a different epoch than you assumed — 1601 is the Windows FILETIME epoch and 1900 is the NTP epoch. Convert from the correct epoch to get the right date.

Summary

Epoch time is a simple idea with a complicated reality: name an instant as a count of units from a fixed origin. The Unix epoch (1970, in seconds) dominates, but NTP, GPS, Windows, Apple and spreadsheets each chose their own reference point and precision, and a value only means what you think it does if you know both. Keep the Unix epoch in UTC as your internal standard, convert other epochs explicitly at the edges, store time in 64-bit fields with documented units, and use the digit count as a fast sanity check. Do that, and the timestamps flowing between your systems stay consistent instead of drifting into 1601 or 50,000 AD.

Treat every timestamp you meet as a number that means nothing until you know its epoch and unit, and the occasional date stuck in 1601 or projected into the far future stops being a baffling glitch and becomes a simple mismatch you can diagnose and correct. That habit of asking "from when, and in what unit?" before trusting any timestamp is the single most useful thing to take away from this guide, and it will serve you across every platform and protocol you work with.

👉 Decode any timestamp with our free tool →

AZ Utils Editorial

AZ Utils Editorial

Finance & web-tools writer

AZ Utilis writes practical, plain-English guides on calculators, finance and everyday web tools, drawing on years of experience helping beginners and small businesses get the numbers right.

Development

How to Format JSON (Beautify & Minify)

How to format JSON — beautify it for readability or minify it for production — in tools, editors, the command line and code, with the why behind each.

AZ Utils Editorial · · 10 min read