Skip to content

Unix Timestamps and Timezone Handling

Sep 2, 2026 · Formats & Standards

A Unix timestamp is a single integer counting the seconds elapsed since midnight UTC on 1 January 1970, and it names an exact moment in time without any timezone attached. That simplicity is why timestamps are everywhere in databases, log files, APIs, and file metadata. But the same simplicity hides traps: seconds versus milliseconds, the difference between an instant and its human display, and a famous overflow waiting in January 2038. This article walks through each so you can store and convert time correctly.

What exactly is the Unix epoch?

The Unix epoch is the fixed reference point 1970-01-01T00:00:00Z, and a timestamp is simply how many seconds have passed since then. The letter Z means Zulu time, another name for UTC. Because the starting line is fixed and universal, the number that results is unambiguous: the same timestamp refers to the same instant everywhere on Earth at once.

Two details matter. First, the count deliberately ignores leap seconds; Unix time pretends every day has exactly 86,400 seconds, which keeps arithmetic simple at the cost of not being a perfect physical clock. Second, timestamps can be negative. A moment before 1970 is a negative number, so the scheme covers history as well as the future.

To convert by hand, you divide and take remainders. There are 86,400 seconds in a day, so a timestamp divided by 86,400 gives whole days since the epoch, and the remainder gives the time within that day. Computers do exactly this, then apply calendar rules for months and leap years.

Seconds or milliseconds: how do I tell them apart?

The fastest tell is digit count: a seconds-based timestamp for any date near today has 10 digits, while a milliseconds-based one has 13. Unix systems, most SQL databases, and many APIs count in whole seconds. JavaScript, Java, and several other runtimes count in milliseconds since the same epoch, multiplying by 1,000.

Mixing the two is one of the most common time bugs in software. Feed a milliseconds value into a function expecting seconds and you land roughly 50,000 years in the future; feed seconds into a milliseconds function and you land in January 1970, moments after the epoch. Both failures are obvious once you know the symptom.

Value Interpreted as Resulting date (UTC)
1700000000 seconds 14 November 2023, 22:13:20
1700000000 milliseconds 20 January 1970, 08:13:20
1700000000000 milliseconds 14 November 2023, 22:13:20
1700000000000 seconds Year 55,865 (obviously wrong)

Some systems go further into microseconds (16 digits) or nanoseconds (19 digits). The rule generalizes: know the unit your source produces before you do arithmetic, and normalize everything to one unit inside your code. When a date lands in 1970 or in the far future, a unit mismatch is the first thing to check. A quick Unix timestamp converter that shows both the seconds and milliseconds interpretation side by side makes that diagnosis immediate.

Why do timestamps say UTC but my dates show local time?

Because a timestamp is always UTC, and the local time you see is a display transformation applied on top of it. The stored number never changes; only the human-readable rendering does. This separation is the single most important idea in timezone handling: store the instant, format for the viewer.

Suppose an event has timestamp 1700000000. That instant is 22:13:20 on 14 November 2023 in UTC. A user in New York, at UTC minus 5 that time of year, sees it as 17:13:20. A user in Tokyo, at UTC plus 9, sees 07:13:20 the next morning. All three describe the same instant; only the wall-clock label differs. The timestamp is the source of truth and each viewer applies their own offset.

Instant (stored):   1700000000  (UTC)
UTC display:        2023-11-14 22:13:20
New York (UTC-5):   2023-11-14 17:13:20
Tokyo   (UTC+9):    2023-11-15 07:13:20

The practical guidance follows directly. Store timestamps, or ISO 8601 strings with an explicit UTC marker, on the server and in the database. Convert to the user’s local timezone only at the last moment, when you render. If you store local times without an offset, you lose the information needed to compare or order events reliably, and daylight-saving transitions turn into genuine ambiguity where a local time either occurs twice or never occurs at all.

What is ISO 8601 and why prefer it for display?

ISO 8601 is a standardized text format for dates and times, written largest unit to smallest, such as 2038-01-19T03:14:07Z. The date and time are joined by a T, and a trailing Z marks UTC. An explicit offset like +09:00 can appear instead of Z to encode a specific local zone.

ISO 8601 has three properties that make it excellent for interchange and logs. It is unambiguous: unlike 01/02/03, which could be three different dates depending on national convention, the ISO form has exactly one reading. It is sortable: because it runs from most to least significant, plain alphabetical text sorting also sorts chronologically. And it is self-describing: the offset or Z tells you the timezone rather than leaving you to guess.

Format Example Timezone clear? Sorts as text?
Unix seconds 2147483647 Yes (always UTC) Yes (numeric)
ISO 8601 UTC 2038-01-19T03:14:07Z Yes Yes
ISO 8601 offset 2038-01-19T12:14:07+09:00 Yes Mostly
US locale 1/19/2038 3:14 AM No No

A useful pattern is to keep numeric timestamps as the internal canonical form for storage and arithmetic, and to emit ISO 8601 strings whenever a human or another system needs to read the value. The two are easy to convert between and each is strong where the other is weak.

What is the Year 2038 problem, precisely?

The Year 2038 problem is an integer overflow: systems that store Unix time in a signed 32-bit integer can only count up to 2,147,483,647 seconds, which is 03:14:07 UTC on 19 January 2038. One second later the counter overflows and wraps to the most negative value it can hold, which the software then reads as a date in December 1901.

The arithmetic is exact and worth understanding. A signed 32-bit integer uses one bit for sign and 31 bits for magnitude, giving a maximum of 2 to the 31st power minus 1, which is exactly 2,147,483,647. Converting that many seconds from the 1970 epoch lands precisely on 2038-01-19T03:14:07Z. Add one more second and the number can no longer be represented as a positive 32-bit value; it flips negative, so time appears to jump backward by more than a century.

Max signed 32-bit int:   2,147,483,647 seconds
That instant:            2038-01-19 03:14:07 UTC
Plus one second:         overflow -> negative
Misread as:              1901-12-13 (approximately)

This is the modern echo of the Year 2000 problem, and it is already relevant, because software that computes future dates, expiry timers, mortgage schedules, certificate lifetimes, can reach beyond 2038 today. The fix is straightforward and widely deployed: use a 64-bit integer for time. A signed 64-bit counter of seconds covers a span far longer than the age of the universe in both directions, so the overflow effectively disappears. Most current operating systems, languages, and databases already use 64-bit time, but embedded systems, old file formats, and legacy protocols that hard-coded 32 bits remain the places to audit.

How should I handle timestamps safely in practice?

Store instants in UTC, keep one consistent unit, and only localize at the edge. In concrete terms: persist times as UTC timestamps or ISO 8601 strings with a Z or explicit offset; decide up front whether your codebase counts seconds or milliseconds and convert everything to that unit at the boundary; use 64-bit integers so 2038 is a non-issue; and defer timezone conversion until you render for a specific user.

When you are debugging a stored value by hand, remember that our converter, like the rest of the tools here, runs entirely in your browser, so the timestamps you paste never leave your machine. That local-only design means you can safely inspect timestamps pulled from logs or a database without worrying about leaking data to a third party, though as always you should avoid pasting genuine production secrets into any tool. Keep the model clear, one number, always UTC, formatted per viewer, and time stops being a source of surprises.

Frequently asked questions

What is a Unix timestamp?

It is the number of seconds elapsed since the Unix epoch, midnight UTC on 1 January 1970, not counting leap seconds. It is a single number that names a moment in time independent of any timezone.

How do I tell seconds from milliseconds?

A seconds timestamp for a current date has 10 digits; a milliseconds timestamp has 13. If a date lands in 1970, you likely treated milliseconds as seconds, or vice versa.

Does a Unix timestamp have a timezone?

No. A Unix timestamp is always in UTC by definition. Timezones only enter when you format that instant into a human-readable local date and time for display.

What is the Year 2038 problem?

A signed 32-bit integer maxes out at 2,147,483,647 seconds, which is 03:14:07 UTC on 19 January 2038. One second later it overflows to a negative number, misreading the time as December 1901.

What is ISO 8601?

ISO 8601 is a text date-time format like 2038-01-19T03:14:07Z. The trailing Z means UTC. It is human-readable, sorts correctly as text, and removes the ambiguity of numeric-only formats.