← Back to all articles

Unix Timestamps 101: Seconds vs Milliseconds, UTC and Timezones

TimePitfalls

What a timestamp is

A Unix timestamp = the number of seconds since 1970-01-01 00:00:00 UTC. It is timezone-independent: at any given moment, every corner of the world reads the same value — which is exactly why it is ideal for storing and transmitting time.

Seconds, milliseconds, microseconds

  • 10 digits = seconds (Linux/databases);
  • 13 digits = milliseconds (Java, JavaScript);
  • 16 digits = microseconds (some high-precision systems).

Mixing them up yields dates in 1970 or 50,000 years from now. When a conversion looks absurd, count the digits first.

Timezone affects display only

The same timestamp shows as 19:00 in UTC+8 and 11:00 in UTC — the display changes, not the value. Most "my times don't match" bugs come from storing local time as if it were UTC (or the reverse).

Practical rules

  1. Store UTC timestamps or ISO 8601 strings in the database;
  2. Localize on the frontend for each user's timezone;
  3. Watch the 2038 problem: 32-bit second timestamps will overflow — use 64-bit in new systems.

Cheat sheet by language and database

EnvironmentCurrent timestampDigits
JavaScriptDate.now()13 (milliseconds)
Pythontime.time()10 (seconds, fractional)
JavaSystem.currentTimeMillis()13 (milliseconds)
Gotime.Now().Unix()10 (seconds)
MySQLUNIX_TIMESTAMP() / FROM_UNIXTIME(1700000000)seconds
PostgreSQLEXTRACT(EPOCH FROM now())seconds (fractional)

Verifying on the command line

# Linux / macOS: timestamp -> readable UTC time
date -u -d @1700000000

# Reverse: readable time -> timestamp
date -u -d '2023-11-14 22:13:20' +%s

# Render in a specific timezone
TZ=Asia/Shanghai date -d @1700000000

Four pitfalls to avoid

  • Mixing digit lengths: reading 10-digit seconds as milliseconds yields 1970-01-01; the reverse lands 50,000 years ahead;
  • Storing local time as UTC: sending "2026-09-23 10:00" without an offset shows the wrong moment elsewhere;
  • Comparing raw strings: ISO strings versus epoch values, or times with different offsets, compare unreliably;
  • Ignoring DST: some regions shift twice a year — schedule across timezones in UTC.

Storing and displaying

Store and transmit UTC timestamps or ISO 8601 with Z or an offset. Render with Intl.DateTimeFormat per user. The same instant appearing as different local times is correct behaviour, not a bug.

Real-world cases: three timezone-related failures

  1. "Logs are 8 hours off": the server records UTC and the frontend shows local — a normal conversion, not a bug.
  2. "Stored 13 digits but parsed as 10": a unit mismatch causes a 1000x error; always agree on the unit across services.
  3. "Wrong on the DST switch day": storing UTC timestamps avoids it by nature; only localized format strings hit timezone rules.

FAQ

Store seconds or milliseconds? Either, as long as it is consistent end-to-end; milliseconds are finer-grained and Date.now() defaults to them. Can a timestamp be negative? Yes, for dates before 1970. How do I avoid the 2038 problem? Use 64-bit integers. How should I display it? Format per the user's timezone — do not dump a raw number.

Try them: timestamp converter, Cron expression

Rules for passing time between systems

  1. Transmit in UTC: APIs, messages and logs should use a standard format with an explicit zone, leaving localisation to the presentation layer. Local time strings on the wire cause ambiguity across regions.
  2. Store by purpose: values you compute, compare or sort on belong in integer or zone-aware types; display-only history can be text, but with a consistent format and stated zone.
  3. Avoid implicit conversion: many languages interpret a zoneless string in local time, giving different results per machine. Specify the zone when parsing, or accept only inputs with an offset.
  4. Watch for DST: transition days contain skipped or repeated hours, so scheduled jobs and duration maths should work in absolute time.
  5. Keep precision consistent: mixing seconds and milliseconds is the top cause here — state the unit in the contract and validate digit count or range.

Time defects rarely show up in a demo but surface during multi-region deployment, year-end settlement and scheduled jobs, so rules pay off early.