DEV Community

Devanshu Biswas
Devanshu Biswas

Posted on

The Unix Timestamp, Demystified (and the 1000 Bug That Bites Everyone)

A Unix timestamp is one of the most common things in software and one of the most quietly misunderstood. Let's fix that.

What it actually is

It's a single integer: the number of seconds since midnight UTC on 1 January 1970 — "the epoch". No timezone, no formatting, just a count from one fixed point. That's why it's the ideal way to store and compare moments: two events order by comparing integers, with zero ambiguity about which timezone was meant.

The bug everyone hits: seconds vs milliseconds

Unix tools and most APIs use seconds. JavaScript's Date uses milliseconds. Mix them up and you're off by a factor of 1000 — a date in 1970, or in the year 52,000. You can tell them apart by size: a "now" timestamp is ~10 digits in seconds, ~13 in milliseconds. So detect and normalise:

const digits = String(Math.trunc(n)).length;
const ms = digits <= 11 ? n * 1000     // seconds
         : digits <= 14 ? n            // milliseconds
         : Math.round(n / 1000);       // microseconds
Enter fullscreen mode Exit fullscreen mode

A Date is an instant, not a string

A Date wraps a single millisecond count — an absolute instant. Everything you see (UTC text, local time, ISO) is just a rendering of that one instant. You never "convert" the instant between timezones; you only choose how to display it.

const d = new Date(ms);
d.toISOString();  // 2025-07-01T12:00:00.000Z  <- store THIS
d.toUTCString();  // Tue, 01 Jul 2025 12:00:00 GMT
Enter fullscreen mode Exit fullscreen mode

Local and relative time via Intl

The browser's Intl handles the messy parts for free:

Intl.DateTimeFormat().resolvedOptions().timeZone;   // "Asia/Kolkata"
new Intl.RelativeTimeFormat(undefined, {numeric:"auto"})
  .format(-3, "day");                                // "3 days ago"
Enter fullscreen mode Exit fullscreen mode

Two famous gotchas

  • JavaScript months are 0-based. new Date(2025, 0, 1) is January. Off-by-one bugs live here.
  • The Year 2038 problem. Systems storing the timestamp in a signed 32-bit integer overflow at 2,147,483,647 seconds — 03:14:07 UTC on 19 January 2038 — and wrap to a negative date. The fix everywhere is 64-bit timestamps.

The golden rules

Store UTC (or epoch). Convert to local only for display. Never hand-roll date maths — leap seconds, DST, and timezone history will get you; lean on Date, Intl, and the modern Temporal API.

Try the live converter (auto-detects the unit, shows every format, ticks in real time):
https://dev48v.infy.uk/solve/day22-timestamp-converter.html

Top comments (0)