Unix Timestamps Explained: Seconds, Milliseconds and Time Zones
What a Unix timestamp is, how to tell seconds from milliseconds, why time zones do not change it, the 2038 problem, and how to convert epoch values in code.
Updated
A Unix timestamp is a count of seconds since the Unix epoch, 00:00:00 UTC on 1 January 1970. 1696118400 means 1,696,118,400 seconds after that moment, which is midnight UTC on 1 October 2023. It is the same number in every country, because the time zone only enters when you turn the count into a calendar date for a human to read.
Why computers count seconds
Dates are awkward to store and compare. Months have different lengths, years sometimes have 366 days, and every region writes the parts in a different order. A single integer avoids all of that. Two timestamps can be compared with a less-than sign, subtracted to get a duration, sorted as plain numbers and stored in a fixed number of bytes.
That is why databases, log files, JWT tokens, cache headers and most APIs exchange time as an epoch value. A few landmarks help you recognise one when you see it:
0is 1970-01-01T00:00:00Z, the epoch itself.1000000000is 2001-09-09T01:46:40Z, the billionth second.1696118400is 2023-10-01T00:00:00Z.1791676800is 2026-10-11T00:00:00Z.2147483647is 2038-01-19T03:14:07Z, the 32-bit limit.
Negative values are allowed and mean dates before 1970, though not every system handles them.
Seconds versus milliseconds
The original definition counts seconds, and that is what Unix tools, Python's time.time() and most databases return. JavaScript broke the convention. Date.now() returns milliseconds, so the same instant appears as 1696118400000. Java's System.currentTimeMillis() and many logging frameworks follow JavaScript.
Mixing the two is the most common timestamp bug. Pass a millisecond value where seconds are expected and the date lands around the year 55,000. Pass seconds where milliseconds are expected and every date becomes 20 January 1970. The quick check is the digit count: present-day values have 10 digits in seconds and 13 in milliseconds. Some systems go further, with 16 digits for microseconds and 19 for nanoseconds.
Converting is a multiplication or division by 1000. In JavaScript, seconds come from Math.floor(Date.now() / 1000), and a seconds value becomes a date with new Date(ts * 1000). The Unix Timestamp Converter detects the unit from the length automatically and shows the decoded date alongside its ISO 8601 form, which saves you from guessing.
Time zones do not change the number
A timestamp names an instant, not a wall-clock time. 1696118400 is midnight on 1 October in London, but it is 20:00 on 30 September in New York, 05:30 on 1 October in Mumbai and 09:00 on 1 October in Tokyo. All four are the same instant and the same number. Only the display differs.
This is why the sensible rule for any system is: store and transmit timestamps in UTC, and convert to local time at the last possible moment, in the user interface. If you store a local time instead, you lose the instant. "2:30 on 5 November" happens twice in New York when clocks go back, and never on the spring date when they skip forward.
Daylight saving time is the main reason to avoid local-time arithmetic. Adding 86400 seconds to a timestamp always advances exactly one day of real time, but that day may be 23 or 25 hours on the local clock. If you need "same time tomorrow" in a user's zone, do the calculation in calendar terms with a timezone-aware library, not by adding seconds.
When you need to see what a given instant looks like across offices, the Timezone Converter takes one date and time and lists the equivalent in over 30 zones, which is quicker than reasoning about offsets by hand.
Leap seconds and the 2038 limit
Unix time pretends every day has exactly 86400 seconds. Real days occasionally include a leap second, and when one happens the system clock repeats or stretches a second rather than counting to 60. For almost all applications this is invisible, but it is why Unix time is not quite the same as the number of real seconds elapsed since 1970.
The 2038 problem is more practical. A signed 32-bit integer tops out at 2147483647. One second later, on 19 January 2038 at 03:14:08 UTC, it wraps to a large negative number, which decodes to December 1901. Modern operating systems, languages and databases use 64-bit values and are safe for the next 292 billion years. The risk sits in old embedded devices, legacy file formats and any schema that chose INT instead of BIGINT for an epoch column.
Working with timestamps in code
The conversions are built into every language, but the shape differs:
- Shell:
date +%sprints the current timestamp, anddate -u -d @1696118400decodes one on Linux. - Python:
datetime.fromtimestamp(1696118400, tz=timezone.utc)andint(dt.timestamp()). - JavaScript:
new Date(1696118400 * 1000).toISOString()andMath.floor(date.getTime() / 1000). - SQL:
to_timestamp(1696118400)in PostgreSQL,FROM_UNIXTIME(1696118400)in MySQL. - Excel:
=A1/86400 + DATE(1970,1,1)turns a seconds value into a date serial.
Durations are just subtraction. Two timestamps 1696118400 and 1696204800 differ by 86400, which is one day. Divide by 3600 for hours or 604800 for weeks. When the result needs to be expressed in calendar units such as "2 years, 3 months and 14 days", plain subtraction is no longer enough because month lengths vary. The Duration Calculator handles that breakdown from two dates and also shows the totals in days, hours and seconds.
More converters for dates, cron expressions and schedules live in the datetime category.
Try it
Paste 1696118400 into the Unix Timestamp Converter to see 1 October 2023 in UTC, then paste 1696118400000 and confirm it detects milliseconds and resolves to the same instant.