Unix Timestamps, Explained
After reading this you will be able to convert any Unix timestamp to a human date in the correct timezone, convert dates back to seconds, tell seconds apart from milliseconds, and avoid the three mistakes that produce dates off by hours, thousands of years, or one day.
What a Unix timestamp is
A Unix timestamp is a single integer: the number of seconds that have elapsed since 1970-01-01 00:00:00 UTC, a moment called the epoch. That is the whole definition. The number 1700000000 means 1,700,000,000 seconds after the epoch, which is 2023-11-14 22:13:20 UTC.
Because the count is tied to UTC and stored as one number, it is unambiguous. The same integer refers to the same instant everywhere on Earth. What changes between users is only how that instant is displayed. A timestamp of 1700000000 shows as 22:13:20 in London (UTC in November) and 17:13:20 in New York (UTC-5), but it is the same moment.
Many systems store milliseconds instead of seconds. JavaScript's Date.now() returns milliseconds, so the same instant becomes 1700000000000, a number a thousand times larger. Telling the two apart is the first practical skill, and this article covers it below.
When to use it, and when not to
Reach for a Unix timestamp when you need to store or compare instants without carrying timezone baggage. Log lines, database created_at columns, cache expiry, JWT exp and iat claims, and rate-limit windows all use epoch seconds because subtraction gives you elapsed time directly. If event A has timestamp 1700000000 and event B has 1700000075, then B happened 75 seconds after A. No timezone math required.
Do not use a raw timestamp when a human needs to read it, and do not use one for future civil times that depend on local rules. If you schedule a meeting for "9am next March," storing the epoch seconds you computed today can be wrong: a government may change its daylight-saving rules before March arrives. For future wall-clock events, store the local date, time, and IANA zone name (for example Europe/Paris) and resolve to an instant later.
Unix time ignores leap seconds. Since 1972, 27 leap seconds have been inserted into UTC, but the Unix count never advanced for them. A Unix timestamp is therefore not a true count of elapsed SI seconds since 1970; it is a count of "days times 86400 plus seconds into the day." For everyday conversion this never matters.
The conversion formula and intuition
Splitting a timestamp into a calendar date starts with dividing by the length of a day. Because leap seconds are ignored, every day is exactly 86400 seconds long.
Here t is the timestamp in seconds, \lfloor \cdot \rfloor is the floor (round down), and \bmod is the remainder. The day count is added to the epoch date 1970-01-01 to get the calendar date. The remainder splits into hours, minutes, and seconds:
where s is seconds into the day. The only hard part is turning a day count into a year, month, and day, because months differ in length and leap years add a day. That logic is the Gregorian calendar, and it is why you use a converter instead of doing it by hand. To display in a non-UTC zone, add the zone's offset in seconds before splitting: New York in winter is -18000 seconds (UTC-5).
Worked example: converting 1700000000
The demo uses 1700000000 seconds. Follow the math to reproduce the UTC output.
- Days since epoch: \lfloor 1700000000 / 86400 \rfloor = 19675 whole days.
- Seconds into the day: 1700000000 \bmod 86400 = 79600.
- Hours: \lfloor 79600 / 3600 \rfloor = 22. Minutes: \lfloor (79600 \bmod 3600) / 60 \rfloor = 13. Seconds: 79600 \bmod 60 = 20.
- Add 19675 days to
1970-01-01. That lands on2023-11-14. - Combine:
2023-11-14 22:13:20 UTC, or in ISO 8601,2023-11-14T22:13:20Z.
To show the same instant in New York during November (UTC-5), subtract 18000 seconds: 79600 - 18000 = 61600, which is 17:13:20, still on 2023-11-14. The date did not roll back because the offset did not push the time below zero.
Reading the different output formats
The same instant appears in several standard shapes. Each answers a different need.
- ISO 8601
2023-11-14T22:13:20Z. Sortable as plain text, machine-friendly, the default for JSON APIs. The trailingZmeans UTC (Zulu). An offset like+01:00replaces theZfor local zones.- RFC 2822
Tue, 14 Nov 2023 22:13:20 +0000. The format used in email headers and older HTTP dates. Human-readable and still parseable.- Relative time
- "3 months ago" or "in 2 days." Computed as the difference between the timestamp and the current time. It drifts as the clock advances, so it is for display only, never for storage.
Prefer ISO 8601 for anything a program will read again. It sorts correctly with a string comparison because the fields run from most significant (year) to least (second), so 2023-11-14 sorts before 2023-11-15 automatically.
The size of the number tells you the unit
Seconds and milliseconds are the two units you will meet. You can guess the unit from magnitude alone, because a plausible recent date in seconds is about ten digits, while the same date in milliseconds is thirteen digits.
A quick rule for dates between 2001 and 2286: 10 digits are seconds, 13 digits are milliseconds. If you feed 1700000000000 (13 digits) into a converter expecting seconds, you get the year 55839. If you feed 1700000000 into code expecting milliseconds, you get 1970-01-20. When you are unsure, the Epoch Millis vs Seconds Detector classifies a pasted number for you.
Common mistakes
Three errors cause most timestamp bugs.
The most frequent bug is mixing seconds and milliseconds in arithmetic. Subtracting a seconds value from a milliseconds value gives a difference that is off by a factor of 1000. Always normalize both operands to the same unit before you subtract.
Off by hours from timezone assumptions. A timestamp has no timezone; it is always UTC by definition. The offset appears only when you format. If your displayed time is wrong by a whole number of hours, you formatted in the wrong zone, not stored the wrong number.
Off by one day at midnight. Converting 2023-11-14 00:30 UTC to New York time (UTC-5) gives 2023-11-13 19:30. The date rolled back a day because the offset pushed the local time before midnight. This is correct behavior, but it surprises people comparing "the date" across zones.
The year 2038 overflow. A signed 32-bit integer maxes out at 2147483647, which is 2038-01-19 03:14:07 UTC. One second later it wraps to a large negative number, which formats as 1901-12-13. Systems that store epoch seconds in int32 will break. Use 64-bit storage, which lasts about 292 billion years.
Related tools
When a timestamp drives a schedule, the Cron Expression Parser explains a cron string and previews its next run times, which pairs naturally with reading the current epoch. When you need sortable identifiers that also carry a timestamp, the UUID / ULID / Nano ID Generator produces UUID v7 and ULID values whose leading bits encode millisecond time, so they sort in creation order.
Frequently asked questions
Why does my timestamp show the wrong time?
Almost always a timezone display issue. The stored integer is UTC. Check which zone your converter or code is formatting in. A whole-hour error points to a timezone offset; a factor-of-1000 error points to a seconds versus milliseconds mixup.
What is the largest Unix timestamp?
For signed 32-bit storage the maximum is 2147483647 (2038-01-19 03:14:07 UTC). For 64-bit storage the practical limit is far beyond any date you will use.
How do I convert milliseconds to seconds?
Divide by 1000 and drop the fractional part: 1700000000000 / 1000 = 1700000000. To go the other way, multiply seconds by 1000.
Does the converter send my data anywhere?
No. The conversion runs entirely in your browser. Nothing you paste leaves your device.
Why do dates ignore leap seconds?
Unix time defines every day as exactly 86400 seconds so that division stays simple. The 27 leap seconds added to UTC since 1972 are never counted, which keeps the math predictable at the cost of not matching true elapsed SI seconds.