Unix timestamps and time zones explained
8 min read · Updated 4 October 2026
Computers need a way to record moments in time that is unambiguous, easy to compare and independent of where in the world the computer is. The most widespread answer is the Unix timestamp: a single number counting the seconds since a fixed starting point. You will find timestamps in databases, log files, APIs, file metadata, cookies and tokens.
Timestamps themselves are simple. The difficulties start when you turn them into the local dates and times people read, which involves time zones, daylight saving time, and a surprising number of ways to get it slightly wrong. This guide covers both.
What a Unix timestamp is
A Unix timestamp is the number of seconds that have elapsed since 00:00:00 UTC on 1 January 1970, a moment known as the Unix epoch. Some reference points:
| Timestamp | Date and time (UTC) |
|---|---|
| 0 | 1970-01-01 00:00:00 |
| 1,000,000,000 | 2001-09-09 01:46:40 |
| 1,700,000,000 | 2023-11-14 22:13:20 |
| 1,767,225,600 | 2026-01-01 00:00:00 |
| 1,791,124,200 | 2026-10-04 14:30:00 |
| 2,000,000,000 | 2033-05-18 03:33:20 |
| 2,147,483,647 | 2038-01-19 03:14:07 |
Important properties:
- A timestamp is the same everywhere. At any given instant, a computer in Tokyo and one in New York produce the same number. Time zones only matter when you display it.
- It ignores leap seconds. Every day is treated as exactly 86,400 seconds. This keeps the arithmetic simple; the occasional leap second is absorbed by system clocks.
- Dates before 1970 are negative numbers. −86,400 is 31 December 1969, 00:00 UTC.
The last row of the table is the largest value a signed 32-bit integer can hold. Systems that still store timestamps in 32 bits will overflow one second later: the "Year 2038 problem". Modern operating systems and languages use 64-bit values, which last for billions of years, but old embedded devices and file formats can still be affected.
Seconds, milliseconds, microseconds
Different systems count in different units, and mixing them up is the single most common timestamp bug. The number of digits is a good clue for current dates:
| Digits | Unit | Example for 2026-10-04 14:30:00 UTC | Typical source |
|---|---|---|---|
| 10 | seconds | 1791124200 | Unix tools, many APIs, JWT tokens |
| 13 | milliseconds | 1791124200000 | JavaScript, Java |
| 16 | microseconds | 1791124200000000 | Some databases, Python with extra precision |
| 19 | nanoseconds | 1791124200000000000 | Go, some logging systems |
What happens when the unit is wrong:
- Reading the seconds value 1791124200 as milliseconds gives 21 January 1970, a date only three weeks after the epoch.
- Reading the milliseconds value as seconds gives a date tens of thousands of years in the future.
If you ever see a date in January 1970 or a year far beyond 3000, a unit mix-up is almost certainly the cause. The timestamp converter detects seconds, milliseconds and microseconds from the number of digits and shows the result in UTC and any time zone, which makes this kind of mistake easy to spot.
Writing dates as text: ISO 8601
When a timestamp has to be written as human-readable text (in a JSON API, a CSV export or a log line), the safest format is ISO 8601 (and the closely related RFC 3339):
2026-10-04T14:30:00Z
2026-10-04T16:30:00+02:00
2026-10-04T10:30:00-04:00
All three lines describe the same instant. The Z means UTC ("Zulu time"), and +02:00 or -04:00 gives the offset from UTC. Year-month-day order sorts correctly as plain text and avoids the ambiguity of formats like 04/10/2026, which means 4 October in most of the world and April 10 in the United States.
A date-time written without an offset, such as 2026-10-04T14:30:00, is a "floating" local time. Different programs interpret it differently (some as UTC, some as the computer's local time), so avoid it in data exchanged between systems.
Offsets are not time zones
These two ideas are often confused:
- An offset is a fixed difference from UTC, such as
+01:00or-05:00. - A time zone is a region's set of rules over time: its normal offset, when daylight saving time starts and ends, and how those rules have changed historically. Time zones are identified by names from the IANA time zone database, such as
Europe/London,America/New_YorkorAsia/Kolkata.
London is not "UTC+1". It is UTC+0 in winter and UTC+1 in summer, and the date of the switch follows rules that have changed several times in history. Storing only an offset loses that information; storing the zone name keeps it.
Avoid abbreviations like "EST" or "IST" in data. Many are ambiguous (IST is used for India, Ireland and Israel, and CST for both US Central and China Standard Time), and some, like "EST", are used loosely to mean "Eastern time" even in summer, when the correct label would be EDT.
Converting a timestamp to local time
Take the timestamp 1791124200, which is 2026-10-04 14:30:00 UTC. Shown in several zones:
| Zone | Local time | Offset on that date |
|---|---|---|
| UTC | 4 Oct, 14:30 | +00:00 |
| America/New_York | 4 Oct, 10:30 | −04:00 (daylight time) |
| Europe/London | 4 Oct, 15:30 | +01:00 (summer time) |
| Asia/Kolkata | 4 Oct, 20:00 | +05:30 |
| Asia/Tokyo | 4 Oct, 23:30 | +09:00 |
| Australia/Sydney | 5 Oct, 01:30 | +11:00 (daylight time began on 4 Oct) |
Two details are worth noticing. India's offset includes half an hour, as do several others (and Nepal's is +05:45), so code that assumes whole-hour offsets is wrong. And Sydney is already on the next calendar day: the date of an event can differ between zones, not just the hour.
To compare the same moment across several cities, including how the offsets shift with daylight saving, use the time zone planner.
Daylight saving: days that are not 24 hours long
In zones with daylight saving time, two days a year have an unusual length in local time. In London in 2026:
- 29 March has only 23 hours. At 01:00 GMT, clocks jump to 02:00 BST. Local times from 01:00 to 01:59 never happen that day.
- 25 October has 25 hours. At 02:00 BST, clocks go back to 01:00 GMT, so every time from 01:00 to 01:59 happens twice.
This creates three classic bugs:
- "Add a day" is not the same as "add 86,400 seconds". Adding 86,400 seconds to midnight on 28 March 2026 in London gives midnight on 29 March, as expected. Adding 86,400 seconds to midnight on 29 March gives 01:00 on 30 March, because that day was only 23 hours (82,800 seconds) long. If you want "the same local time tomorrow", use your language's calendar-aware date functions with a time zone, not raw second arithmetic.
- Non-existent times. "01:30 on 29 March 2026, Europe/London" does not exist. Software has to choose what to do (usually shifting it forward to 02:30), and different libraries choose differently.
- Ambiguous times. "01:30 on 25 October 2026, Europe/London" happens twice, an hour apart. Without the offset (
+01:00or+00:00), you cannot tell which one is meant.
Duration calculations have the same issue. A shift that runs from 22:00 on 24 October to 06:00 on 25 October in London lasts 9 hours, not 8, because of the repeated hour. Payroll and booking systems need to work in UTC or use time-zone-aware arithmetic to get this right.
Storing time correctly
A practical set of rules:
For things that have already happened (log entries, orders, sign-ups, file changes), store a UTC timestamp (or an ISO 8601 string with Z). Convert to local time only when displaying it. The original instant can never be misinterpreted.
For future events defined in local time (a meeting at 09:00 New York time next July, a shop that opens at 08:00 every day), store the local date and time plus the time zone name, and convert to UTC when needed. Time zone rules are set by governments and occasionally change with little notice. If you store a 09:00 New York meeting on 15 July 2026 as 13:00 UTC (timestamp 1784120400) and the rules change before then, your stored instant would display at the wrong local time. Storing "2026-07-15 09:00, America/New_York" lets the software apply whatever rules are in force.
For dates without a time (birthdays, due dates, public holidays), store just the date. Converting a date to a timestamp at midnight UTC is a well-known source of "off by one day" bugs: midnight UTC on 4 October is still 3 October in the Americas, so the birthday shows a day early.
A related trap exists in JavaScript: new Date("2026-10-04") is interpreted as midnight UTC, but new Date("2026-10-04T00:00") is interpreted as midnight local time. The two can show different dates for the same input string.
Counting days between dates
Counting calendar days is a calendar question, not a timestamp question. Subtracting two timestamps and dividing by 86,400 works most of the time but goes wrong across daylight-saving changes (a 23-hour day becomes 0.958 of a day) and when the two times fall at different hours. For things like "how many days until the deadline" or "how many working days in this period", the date calculator counts calendar days and working days directly, and can exclude weekends and your own list of holidays.
Common mistakes
- Mixing seconds and milliseconds, giving dates in 1970 or the far future.
- Using the server's local time zone in stored data. Servers move between regions, and cloud machines are usually set to UTC anyway. Be explicit.
- Storing offsets instead of zone names for future events.
- Hard-coding daylight saving dates. The rules differ between countries (the US and EU switch on different weekends) and change over time. Use an up-to-date time zone database.
- Assuming whole-hour offsets, which breaks for India, Nepal, parts of Australia and others.
- Using ambiguous abbreviations such as IST or CST in data or user interfaces.
- Comparing local time strings from different zones as if they were the same timeline.
FAQ
Is a Unix timestamp in UTC? A timestamp has no time zone at all: it counts seconds from an instant defined in UTC. That is why it is the same everywhere. Any time zone is applied only when converting it to a calendar date and clock time.
How do I get the current timestamp?
On Linux or macOS, date +%s prints it in seconds. In JavaScript, Date.now() returns milliseconds, so divide by 1,000 and round down for seconds. In Python, time.time() returns seconds with a fractional part.
Do timestamps account for leap years? Yes, automatically. Leap years simply contain more days, and therefore more seconds; any conversion library handles them. Only leap seconds are ignored.
Why does my log show the right time in one tool and an hour off in another?
Usually one tool shows UTC and the other shows local time, or one of them interprets a time without an offset as local. Check whether the values include Z or an offset, and convert both to UTC to compare.