Skip to content
NewKitApp

Search tools

Jump to any tool by name

May 28, 2026

Unix Timestamps Explained: Epoch Time for Developers

A Unix timestamp counts seconds since 1970-01-01 00:00:00 UTC — unambiguous, comparable, and everywhere. The catch: some systems count milliseconds, and getting that wrong puts your date millennia off.

Unix Timestamps Explained: Epoch Time for Developers

If you have ever stared at a number like 1716899200 in a database column, a log file, or a JWT payload and wondered when that actually is, you have met the Unix timestamp. It is the lingua franca of time in software — every operating system, every database, and most programming languages have a native way to produce and consume it — and once you internalize a couple of conventions, reading and writing them becomes second nature.

What the number actually means

A Unix timestamp is the count of seconds that have elapsed since the Unix epoch: midnight UTC on January 1, 1970. That origin point is arbitrary but fixed, and because it is a single integer counting elapsed time rather than a calendar date, it sidesteps the entire mess of time zones, daylight saving, and calendar formatting. A given timestamp means the same instant everywhere on Earth.

Two complications are quietly handled for you. Leap seconds are ignored — Unix time pretends every day is exactly 86,400 seconds, which means a real-world UTC second and a Unix second occasionally diverge by a fraction. In practice this matters only for high-precision systems; application code never sees it. Time before 1970 is represented as a negative number, which works fine but is rare outside historical data.

The one convention that actually trips developers up is units. Some systems count seconds, others count milliseconds. JavaScript's Date.now() and Java's System.currentTimeMillis() return milliseconds — a 13-digit number — while the shell's date +%s, Python's default time.time(), and most database columns return seconds — a 10-digit number. Mixing them up produces dates thousands of years in the future or stuck in 1970, which is the single most common timestamp bug.

// JavaScript: milliseconds since epoch
Date.now();                       // 1716899200123 (13 digits)
Math.floor(Date.now() / 1000);   // 1716899200 (seconds)

// Convert a seconds timestamp into a readable date
new Date(1716899200 * 1000).toISOString();
// "2024-05-28T11:46:40.000Z"

Try it: Timestamp Converter

Convert Unix timestamps and date strings to ISO, UTC, local, and relative time.

Why timestamps instead of dates

A calendar string like 2024-05-28T11:46:40Z is human-readable, but it is fragile: parse it naively and you don't know whether it is UTC or local time, you can't be sure the trailing Z was included, and comparing two dates as strings breaks the moment time zones differ. An integer timestamp is unambiguous — it is always UTC, always comparable with simple numeric ordering, and trivially arithmetical.

Want "24 hours from now"? Add 86400 seconds (or 86400000 milliseconds in JavaScript). Want to find the difference between two events? Subtract. There is no Date object overhead, no timezone library to load, and no ambiguity about what the number means. This is why timestamps dominate in logs, databases, cache entries, and anywhere performance or precision matters — including the exp and iat claims inside a JWT.

The tradeoff is readability — 1716899200 tells a human nothing at a glance. That is where a Timestamp Converter earns its keep: paste the number, get the ISO date, the relative time, and the local equivalent instantly, without mental arithmetic.

One more distinction worth knowing: a Unix timestamp is a wall-clock value, meaning it reflects the calendar time as the server's clock reports it, and that clock can drift or jump — for example, when an NTP sync corrects skew, or when a VM wakes from sleep and discovers hours have passed. For measuring elapsed time or ordering events on a single machine, prefer a monotonic clock (such as performance.now() in the browser or clock_gettime(CLOCK_MONOTONIC) on Linux), which is guaranteed never to go backwards. Wall-clock timestamps are for recording when something happened; monotonic clocks are for measuring how long something took — mixing the two up is a subtle source of bugs in timing and retry logic.

Epochs and the year 2038

A 32-bit signed integer can represent values up to 2147483647, which as a Unix timestamp corresponds to 2038-01-19 03:14:07 UTC. One second later, a signed 32-bit counter overflows and rolls negative — to December 1901. This is the famous Y2038 problem, and it affects any system still storing time in a 32-bit time_t.

In practice, virtually all modern systems use 64-bit time values, which don't overflow for hundreds of billions of years — so on a current server, laptop, or phone, this is a non-issue. It does still matter for legacy embedded systems, old binary formats, and any 32-bit integer column in a database that someone naively used to store a timestamp. The fix is migration to 64-bit integers, and the sooner the better for any long-lived system.

Try it: JWT Decoder

Decode a JSON Web Token's header and payload — no signature verification.

Timestamps vs. ISO 8601

These are the two formats you will meet most often, and they are complements rather than competitors:

  • Unix timestamp — best for storage, comparison, and arithmetic. Compact, unambiguous, fast.
  • ISO 8601 string (for example, 2024-05-28T11:46:40Z) — best for human-facing output, for APIs that prioritize readability, and for serialization formats where a string is more natural than a number.

A reasonable rule: store and compute with timestamps, render with ISO 8601. When you accept a timestamp from an untrusted source, always sanity-check the magnitude — a 13-digit value where you expected 10 (or vice versa) is almost always a units mistake, not a real date. And when a timestamp represents an expiration, like a JWT's exp claim, compare it against the current time in the same units; the JWT Decoder shows exp and iat as both raw values and human-readable dates, which makes that kind of check trivial during debugging.