Unix timestamps: seconds vs milliseconds and the 1970 bug
Why some timestamps are 10 digits and others 13, how to spot the difference, and the classic bugs that come from mixing them up.
You paste a number like 1754620800 into a timestamp converter and get 2025-08-08. You paste 1754620800000 and get… 57459-05-27. Same number, different date by a factor of 1000. This is the single most common timestamp bug in development, and it’s entirely about seconds vs milliseconds.
What a Unix timestamp actually is
A Unix timestamp is the number of seconds elapsed since January 1, 1970 at 00:00:00 UTC — the Unix epoch. It’s an integer that grows by one every second.
A few useful landmarks to memorize:
0→ 1970-01-01 (the epoch)1000000000→ 2001-09-09 (the first billion)1700000000→ 2023-11-14 (as of writing this post, we’re just past 1.75 billion)1754000000→ 2025-08
Why milliseconds exist
Many programming languages and databases store time as milliseconds since the epoch because:
- JavaScript’s
Date.now()returns milliseconds. - Java’s
System.currentTimeMillis()returns milliseconds. - Many REST APIs, JSON payloads, and databases (MySQL’s
BIGINTtimestamps, many NoSQL stores) use milliseconds.
So a timestamp in seconds is 10 digits. The same moment in milliseconds is 13 digits. That’s the whole difference — 10 vs 13 digits, and a date that’s off by roughly 273,785 years when you get it wrong.
The two classic bugs
Bug 1: Seconds where milliseconds are expected. You divide by 1000, or you treat a 13-digit value as 10 digits. Result: the date you get is in the year 57000+.
Bug 2: Milliseconds where seconds are expected. You forget to multiply by 1000. Result: you’re off by a factor of 1000 — a timestamp that should be August 2026 becomes August 2023 (about 3 years and 1.5 months earlier, since 1000 seconds ≈ 16.7 minutes, and the gap grows linearly).
The fix in most languages is trivial but easy to forget:
- JavaScript:
new Date(seconds * 1000)for seconds,new Date(milliseconds)for milliseconds. - Python:
datetime.fromtimestamp(seconds)for seconds,datetime.fromtimestamp(milliseconds / 1000)for milliseconds. - Java:
Instant.ofEpochSecond(seconds)vsInstant.ofEpochMilli(milliseconds).
The 2038 problem
There’s a third trap hiding in 32-bit systems. A signed 32-bit integer tops out at 2,147,483,647, which as a Unix timestamp is 2038-01-19 03:14:07 UTC. On systems still using 32-bit integers for time, the clock rolls over to 1901 on that date. Most modern systems use 64-bit time (which won’t overflow for 290 million years), but old embedded systems, file systems, and some databases still store 32-bit time.
How to convert without the guesswork
When you’re staring at a number and unsure whether it’s seconds or milliseconds, the rule of thumb is: 10 digits is seconds, 13 digits is milliseconds. If you see anything else, you’re looking at a different unit entirely (microseconds or nanoseconds are 16 and 19 digits — and if you ever see those, multiply or divide by the right power of 1000).
The fastest way to check: throw the number into a Unix timestamp converter and look at both representations. A good converter shows the seconds, milliseconds, the UTC time, and your local time side by side — which catches the “off by 1000” mistake in one glance instead of after a bug report.