Almost every timestamp inside a computer is the same thing wearing different clothes: a single number counting seconds from one fixed instant in 1970. Understand that number and a whole class of date bugs stops being mysterious. The value that renders as January 1970 when it should say 2023, the log line that is off by exactly one hour, the field that breaks on a specific morning in 2038: all of them trace back to how Unix time is defined and how it is stored. Here is the number in full, with the exact math behind the two failures that catch people most often.
What Unix time actually counts
A Unix timestamp, also called epoch time or POSIX time, is the number of seconds that have passed since 00:00:00 UTC on 1 January 1970. That instant is the epoch, and it is timestamp zero. Every later moment is a positive count up from there, and every earlier moment is a negative count down.
Concretely, the timestamp 1700000000 is 1,700,000,000 seconds after the epoch, which works out to 22:13:20 UTC on 14 November 2023. You can verify this yourself: divide by 86,400, the number of seconds in a day, and you get 19,675 whole days plus a remainder of 79,600 seconds. Nineteen thousand six hundred and seventy five days after 1 January 1970 lands in mid November 2023, and 79,600 seconds is 22 hours, 13 minutes, and 20 seconds into that day. The whole date is recoverable from one integer with nothing but division. Paste any value into the epoch converter to see the human date and the reverse direction side by side.
The number is always UTC, never local
This is the property that makes epoch time worth using and the one people forget first. A Unix timestamp carries no time zone. It is anchored to UTC by definition, so the same number means the same instant whether you read it in Tokyo or Toronto. The timestamp does not become larger in a later time zone; the clock on the wall differs, but the count of seconds since 1970 is identical everywhere at the same instant.
The confusion starts when you display it. Turning 1700000000 into a human date requires you to choose a time zone for the output, and if you pick the server's local zone by accident, the rendered string is off by the server's offset. A value that is correct in the database looks wrong on the screen, and nobody has actually changed the data. When a timestamp displays an hour or several hours off, suspect the display zone before you suspect the stored number. This is also the deeper reason storing a UTC instant is the safe default for a fixed past moment, a point covered in more detail in how to store dates and times in a database.
Seconds or milliseconds: the multiply-by-1000 bug
The single most common epoch bug is a unit mismatch. The original Unix convention counts whole seconds, and most databases, APIs, and standard libraries follow it. JavaScript does not: Date.now() and getTime() return milliseconds, a thousand times larger. Mix the two and dates fly off by decades.
Here is the failure with real numbers. Suppose a backend stores the seconds value 1700000000 for 14 November 2023. A JavaScript front end reads it and does new Date(1700000000) without scaling. JavaScript treats the argument as milliseconds, so it computes 1,700,000 seconds after the epoch instead of 1.7 billion. That is only about 19.7 days, so the date renders as 20 January 1970. The user sees a timestamp from the Nixon administration for an event that happened last year. The fix is one multiplication: new Date(1700000000 * 1000).
A quick sanity check saves you every time. As of the mid 2020s a Unix timestamp in seconds has ten digits, and the same instant in milliseconds has thirteen. If a number you expected to be a recent date has the wrong digit count, you have found your bug before you have written a line of conversion code. The JavaScript date and time guide walks through the language's specific traps here, including why Date stores milliseconds while most systems it talks to do not.
Why leap seconds are quietly ignored
Unix time is defined as though every single day contains exactly 86,400 seconds. That is a small lie. Since 1972, UTC has occasionally had a leap second inserted to keep atomic clocks aligned with the slightly irregular rotation of the Earth, and there have been 27 of them so far. Unix time does not count any of these. When a leap second occurs, the Unix clock either repeats a value or is smeared across nearby seconds by the operating system, so the timestamp stays a clean multiple of 86,400 per day.
The practical consequence is that a Unix timestamp is not a true tally of physical seconds elapsed since 1970: it is short by the number of leap seconds since then. For ordinary scheduling, logging, and display this does not matter at all, and pretending leap seconds do not exist is exactly what keeps date arithmetic simple. It only matters for systems that need sub-second precision across a leap event, such as high-frequency trading or precise astronomy. If that is you, the leap second history lists every insertion and the exact UTC instant it landed.
The year 2038 problem, with the exact arithmetic
The most famous epoch failure is a storage limit, not a logic error. For decades, systems held the timestamp in a signed 32-bit integer. A signed 32-bit value can represent numbers up to 2,147,483,647, and that is the ceiling on how many seconds it can count from the epoch.
Convert that ceiling and it becomes a specific, unavoidable moment. 2,147,483,647 seconds after 1 January 1970 is 03:14:07 UTC on 19 January 2038. At that instant the counter is full. One second later it should read 2,147,483,648, but a signed 32-bit integer cannot hold that number, so it wraps around to the most negative value it can store, -2,147,483,648. A negative timestamp is a date before the epoch, and this particular one is 20:45:52 UTC on 13 December 1901. In a single tick the system's clock jumps from 2038 back to 1901, and any code that compares dates, sorts records, or checks expiry can fail in whatever way that jump provokes.
The fix is already widespread: store the timestamp in a signed 64-bit integer instead. A 64-bit counter of seconds does not overflow for roughly 292 billion years, which retires the problem permanently. Most modern languages, databases, and 64-bit operating systems already use 64-bit time, so a fresh application built today is generally safe by default. The risk lives in older embedded devices, legacy file formats, and any field somewhere that was pinned to 32 bits and never revisited. If you own long-lived systems, 2038 is a real audit item, not a curiosity, in the same family of scheduled-clock hazards as cron jobs misfiring on daylight saving time.
Where you meet epoch time in the wild
Once you recognise the shape of a Unix timestamp you start seeing it everywhere. A JSON Web Token carries its issued-at and expiry times as epoch seconds in the iat and exp claims, which is why a token can look valid to a human but be rejected as expired: the server compared two raw epoch numbers. If you have ever needed to read those claims, the JWT decoder shows them as real dates. HTTP caching headers, cookie expiry, database created_at columns, log lines, and most event streams all lean on the same integer underneath their formatting.
When a timestamp needs to be human readable and portable at the same time, the usual partner to epoch time is ISO 8601, the string format that writes the same instant as 2023-11-14T22:13:20Z. Epoch time is compact and ideal for storage and comparison; ISO 8601 is readable and unambiguous for interchange. Many systems store the integer and render the string, and the ISO 8601 converter moves between the two so you can confirm a value means what you think before it ships.
A worked conversion you can do by hand
To make the mechanics concrete, convert the timestamp 1,000,000,000 without a computer. Divide by 86,400 to get days: 1,000,000,000 divided by 86,400 is 11,574 whole days with a remainder of 4,000 seconds. Eleven thousand five hundred and seventy four days after 1 January 1970 is 9 September 2001. The remaining 4,000 seconds is 1 hour, 6 minutes, and 40 seconds. So the billionth second of the Unix epoch fell at 01:46:40 UTC on 9 September 2001, a moment that was genuinely celebrated by programmers at the time. The point is not the trivia: it is that a date, a time, and a full instant all came out of one integer and two divisions, with no time zone table and no calendar library involved. That is the whole appeal of epoch time.
A checklist for handling Unix timestamps safely
- Confirm the unit before you do any math. Ten digits is almost certainly seconds, thirteen is almost certainly milliseconds. Scale by 1000 in exactly one place.
- Treat every stored timestamp as UTC. Only apply a time zone when you render it for a human, and make that zone an explicit choice, not the server's accident.
- Store the value in a 64-bit integer. Never define a new timestamp column or field as signed 32-bit, and flag any legacy 32-bit field as a 2038 risk.
- Do not expect leap-second accuracy. If your system needs true elapsed physical time across a leap event, handle that explicitly rather than assuming epoch time provides it.
- Test dates before 1970 if your data can reach them. Negative timestamps are valid but trip up some older libraries.
- Keep a converter to hand for spot checks. Reading a raw integer as a real date turns a silent unit or zone bug into an obvious one.
Frequently asked questions
What is a Unix timestamp?
It is a single number: the count of seconds that have elapsed since 00:00:00 UTC on 1 January 1970, which is called the epoch. The value 1700000000 means exactly 1,700,000,000 seconds after that instant, which is 14 November 2023 at 22:13:20 UTC. Because it is one integer anchored to UTC, it names the same instant everywhere on Earth with no time zone attached.
Is a Unix timestamp in seconds or milliseconds?
It depends on the system. The classic Unix convention is whole seconds, and most databases, APIs, and languages use seconds. JavaScript is the notable exception: Date.now() and getTime() return milliseconds. A ten-digit number is almost always seconds and a thirteen-digit number is almost always milliseconds, so check the length before you multiply or divide by 1000.
What is the year 2038 problem?
Systems that store the timestamp in a signed 32-bit integer can only count up to 2,147,483,647 seconds, which is reached at 03:14:07 UTC on 19 January 2038. One second later the counter overflows to a large negative number and the date jumps back to December 1901. The fix is to store the value in a 64-bit integer, which pushes the limit roughly 292 billion years into the future.
Do Unix timestamps account for leap seconds?
No. Unix time is defined as if every day has exactly 86,400 seconds, so it silently ignores the leap seconds that have been inserted into UTC since 1972. This keeps the arithmetic simple but means a Unix timestamp is not a true count of physical seconds since 1970. For almost all software this is the correct and expected behaviour.
Can a Unix timestamp be negative?
Yes. Any instant before the epoch is a negative number. The value -86400 is 31 December 1969 at 00:00:00 UTC, one day before the epoch. Negative timestamps are valid and useful for historical dates, but some older libraries handle them poorly, so test them if your data reaches before 1970.