Utilo

Unix Timestamp Explained: Seconds, Milliseconds, Time Zones and 2038

What Unix time is, why systems use it, how to convert timestamps in every major language, and how to avoid time zone, millisecond and Y2038 bugs.

· 4 min read

Open almost any log file, database table or API response and you will find numbers like 1760000000. That is a Unix timestamp: the number of seconds elapsed since 00:00:00 UTC on 1 January 1970, known as the Unix epoch. It is the most common way computers represent a moment in time, and understanding it prevents a whole class of bugs involving time zones, daylight saving and date parsing.

Why count seconds from 1970?

Early Unix developers needed a simple, compact representation of time. Counting seconds from a fixed recent date fit in a single integer, was easy to compare and subtract, and avoided the complexity of calendars. The date 1 January 1970 was simply a convenient round starting point when Unix was being built.

The advantages still hold today:

  • Time-zone independent. A timestamp identifies an instant, not a wall-clock reading. The same event has the same timestamp in Tokyo, Berlin and São Paulo.
  • Easy arithmetic. The difference between two timestamps is a duration in seconds. Adding 86,400 moves forward one day.
  • Compact and sortable. An integer takes 8 bytes and sorts chronologically.
  • Unambiguous. No confusion between 03/04 meaning March 4 or April 3.

Seconds versus milliseconds

The most frequent timestamp bug is mixing units:

  • Unix tools, most databases, JWTs and many APIs use seconds: 10 digits today, such as 1760000000.
  • JavaScript's Date.now(), Java's System.currentTimeMillis() and many analytics systems use milliseconds: 13 digits, such as 1760000000000.
  • Some systems use microseconds (16 digits) or nanoseconds (19 digits).

Interpreting milliseconds as seconds yields a date tens of thousands of years in the future; the reverse lands you in January 1970. If you ever see "1970-01-21" in a UI, someone passed seconds where milliseconds were expected. A timestamp converter detects the unit by length, which is a quick sanity check.

Converting timestamps in common languages

JavaScript

const nowSeconds = Math.floor(Date.now() / 1000);
const date = new Date(1760000000 * 1000);
date.toISOString(); // "2025-10-09T08:53:20.000Z"

Python

import time, datetime
now = int(time.time())
dt = datetime.datetime.fromtimestamp(1760000000, tz=datetime.timezone.utc)

Always pass tz= in Python; without it, fromtimestamp returns a naive local time that is easy to misinterpret.

SQL (PostgreSQL)

SELECT to_timestamp(1760000000);           -- timestamptz
SELECT extract(epoch FROM now())::bigint;  -- current Unix time

Go

t := time.Unix(1760000000, 0).UTC()
now := time.Now().Unix()

Shell

date +%s                    # current timestamp
date -u -d @1760000000      # GNU date
date -u -r 1760000000       # macOS/BSD date

Time zones: store UTC, display local

A timestamp has no time zone; it is an absolute instant. Problems arise when converting to and from human-readable dates:

  • Parsing a date without a zone. new Date("2026-03-29 02:30") is interpreted in the local time zone of whatever machine runs the code. On a server in UTC and a laptop in Berlin, it produces different timestamps.
  • Daylight saving gaps and overlaps. In zones with DST, some local times do not exist (clocks jump forward) and others occur twice (clocks go back). A timestamp has no such ambiguity.
  • Storing local times. If you store "2026-11-01 01:30" without a zone, you can never be sure which instant it was.

The rule of thumb: store and transmit timestamps or ISO 8601 strings with an explicit offset (2026-10-11T09:30:00Z or +02:00). Convert to the user's local zone only when displaying. Store the user's IANA time zone name (such as Europe/Berlin) separately if you need to schedule things in their local time.

ISO 8601 versus Unix timestamps

ISO 8601 strings like 2026-10-11T09:30:00Z are human-readable and also unambiguous when they include Z or an offset. Many APIs prefer them for readability. Unix timestamps are smaller and faster to compare. Both are fine; the important thing is consistency and always including zone information.

Leap seconds

Earth's rotation is slightly irregular, so official UTC occasionally inserts a leap second. Unix time ignores them: every day is exactly 86,400 seconds, and during a leap second the timestamp repeats or is smeared. For almost all applications, this is invisible. If you work on high-precision timing, use TAI or GPS time instead. International timekeeping bodies have decided to phase out leap seconds by 2035, which will make this even less of a concern.

The Year 2038 problem

Many older systems store Unix time as a signed 32-bit integer, whose maximum value is 2,147,483,647. That corresponds to 03:14:07 UTC on 19 January 2038. One second later, the value overflows to −2,147,483,648, which represents 13 December 1901.

Modern 64-bit operating systems, languages and databases use 64-bit timestamps, which will not overflow for about 292 billion years. Risks remain in:

  • Embedded devices and industrial controllers with long lifetimes.
  • File formats and network protocols with 32-bit time fields.
  • Database columns declared as 32-bit INT holding epoch seconds. MySQL's TIMESTAMP type has a 2038 limit; DATETIME or BIGINT do not.

Audit long-lived data now, especially anything that stores future dates such as certificate expiry or 20-year contracts.

Negative timestamps

Dates before 1970 have negative timestamps. -86400 is 31 December 1969. Most modern languages handle them correctly, but some older APIs and spreadsheets do not, so test historical dates explicitly.

Practical debugging checklist

  1. Count the digits: 10 for seconds, 13 for milliseconds.
  2. Convert to UTC first, then to local time, to separate unit bugs from zone bugs.
  3. Check whether a date string includes Z or an offset before parsing it.
  4. Compare server and client clocks if tokens or signatures fail with "expired" or "not yet valid" errors — see how JWT works for why exp and nbf are Unix seconds.
  5. When scheduling recurring jobs, remember that cron runs in the server's zone; these cron examples cover the details.

Summary

A Unix timestamp is the number of seconds since 1970-01-01 UTC. It is simple, time-zone independent and easy to compute with. Most bugs come from mixing seconds and milliseconds, parsing dates without zones, or storing local times. Store UTC, convert at the edges, use 64-bit integers, and you will rarely have to think about time again.

Related guides