A Unix timestamp is a single number: how many seconds have elapsed since midnight UTC on 1 January 1970. That is the whole design, and its economy is why it is everywhere — in logs, databases, JWTs and APIs. It is also why it needs a tool, because a number like 1752537600 tells a human nothing at all.
Seconds or milliseconds: the factor of 1000
Unix time counts seconds. JavaScript counts milliseconds — Date.now() returns a number a thousand times larger, and so does every JavaScript Date constructor. This mismatch is responsible for more broken timestamps than everything else combined.
The symptom is unmistakable once you know it. Feed a seconds value to something expecting milliseconds and you land in January 1970: the whole span of Unix time so far becomes three weeks. Feed milliseconds where seconds are expected and you get a date fifty thousand years out. Neither errors. Both render happily as a date, which is what makes the bug survive code review.
A quick sanity check: a current timestamp in seconds has ten digits, and one in milliseconds has thirteen. If you are staring at a number and unsure, count the digits before you divide.
A timestamp has no timezone
This is worth internalising, because it dissolves most timezone confusion. A Unix timestamp is an instant — the same moment for everyone alive. It is not in UTC any more than it is in Tokyo time; it simply is. Timezones only enter when you render that instant as a human-readable date, and that is a display decision, not a property of the data.
So "convert this timestamp to UTC" is not really a conversion at all — it is a formatting choice. The timezone selector here changes how the same underlying instant is written out, not what it means. This is also why storing timestamps rather than local date strings saves so much pain: an instant is unambiguous, and "2025-10-26 02:30" is not.
The year 2038 problem is real and already biting
For decades, Unix systems stored time in a signed 32-bit integer. That runs out at 2147483647 seconds, which is 03:14:07 UTC on 19 January 2038. One second later the value overflows, wraps to negative, and the date becomes 13 December 1901.
It sounds like a distant problem and is not. Any system computing a date more than a few years ahead already crosses the line: a thirty-year mortgage, a certificate expiry, a pension projection. Bugs from this were being found in production well before 2020. Most modern platforms have moved to 64-bit time — which pushes the limit past the expected lifetime of the sun — but embedded devices, old file formats and some database columns have not. If you are storing a timestamp in a 32-bit column today, that is a bug with a due date.
Unix time deliberately ignores leap seconds
Here is a fact that surprises even experienced developers: a Unix timestamp is not a true count of elapsed seconds. Since 1972 the world has inserted 27 leap seconds to keep clocks aligned with the Earth's rotation, and Unix time skips every one of them. It defines each day as exactly 86400 seconds, whether or not that day actually had 86400 seconds.
The trade is deliberate. It makes the arithmetic trivial — any date converts to a timestamp with plain division — at the cost of the count being slightly wrong in an absolute sense. It also means the real leap second 23:59:60 is simply not expressible: JavaScript rejects it outright, and Date.parse("2016-12-31T23:59:60Z") returns NaN even though that second genuinely existed. If you need true elapsed time across leap seconds, Unix time is the wrong instrument, and for the other 99.99% of software this trade-off is exactly right.
Ambiguous and impossible local times
Timestamps are clean; local times are not. Twice a year, daylight saving makes local wall-clock time misbehave. When clocks go back in Rome on the last Sunday of October, 02:30 happens twice — a local timestamp of "2025-10-26 02:30" maps to two different instants and nothing in the string tells you which. When clocks spring forward in March, 02:30 does not exist at all.
This is why converting a local date to a timestamp is genuinely lossy in a way the reverse never is. If you are storing appointments, log entries, anything where the exact instant matters, store the timestamp and render the local time on the way out — not the other way round.
Common questions
Is my data sent to a server?
No. This tool is marked "client": the conversion is arithmetic and formatting done in your browser tab, using its own timezone database. Nothing is transmitted.
My timestamp shows as 1970. What went wrong?
Something read seconds as milliseconds. Multiply by 1000 and the date will make sense. It usually means a value that was correct in a database was handed straight to a JavaScript Date constructor without conversion — Date expects milliseconds and will not warn you.
Can a timestamp be negative?
Yes — it just means before 1970. A timestamp of -1 is 31 December 1969 at 23:59:59 UTC. Most software handles this correctly, but not all of it: date-of-birth fields for anyone born before 1970 have historically been a rich source of bugs in systems whose authors assumed timestamps were always positive.
Why does the same timestamp show a different hour on my colleague's screen?
Because you are in different timezones, and that is correct behaviour rather than a bug. The instant is identical; only its rendering differs. If you need everyone to see the same wall-clock reading — a scheduled maintenance window, say — state the timezone explicitly alongside it, or use UTC and say so.
Should I store dates as timestamps or as strings?
Store the instant, whether as an integer timestamp or a proper timestamp-with-timezone column — your database almost certainly has one, and it will handle ranges and arithmetic that a bare integer cannot. What to avoid is a local date string with no zone attached: it is ambiguous twice a year at daylight-saving boundaries, and there is no way to recover the missing information later.