712Tools
5 min read

The Unix timestamp cheat sheet every developer wishes they had bookmarked

Seconds vs milliseconds vs microseconds, ISO 8601 vs RFC 3339, timezones, DST, leap seconds โ€” the reference for every 'wait, is this in ms?' moment.

Seconds, milliseconds, microseconds

Every timestamp bug starts with a unit mismatch. The three you'll actually see:

  • Seconds โ€” Unix's original unit. 10 digits until year 2286. Used by time() in C, time.time() in Python (as a float), Time.now.to_i in Ruby, and most cron systems.
  • Milliseconds โ€” JavaScript's Date.now(), Java's System.currentTimeMillis(), most APIs designed after 2005. 13 digits.
  • Microseconds / nanoseconds โ€” Go's time.Now().UnixNano(), database timestamps like Postgres timestamp. 16 or 19 digits.

The fast heuristic: count digits. 10 = seconds. 13 = milliseconds. 16+ = micro or nano.

The Y2K38 problem

Signed 32-bit integers overflow on January 19, 2038 at 03:14:07 UTC. Any system still using 32-bit time_t โ€” mostly embedded devices โ€” silently wraps to 1901. Every modern language and database uses 64-bit now, but check your embedded stack.

ISO 8601, RFC 3339, and JavaScript

ISO 8601 is a large family of date formats. RFC 3339 is a strict subset โ€” the one everyone actually means when they say "ISO date":

2026-08-11T14:30:00Z          (UTC, Z suffix)
2026-08-11T14:30:00.123Z      (with milliseconds)
2026-08-11T14:30:00+02:00     (with timezone offset)

JavaScript's Date.prototype.toISOString() always produces RFC 3339 in UTC. new Date(string) accepts most ISO variants but has one trap: date-only strings ("2026-08-11") parse as UTC, while datetime strings without a timezone ("2026-08-11T14:30") parse as local time. Off-by-one-day bugs come from this.

Timezones the sane way

Three rules:

  1. Store in UTC. Every timestamp in the database, the log, the message queue: UTC. No exceptions.
  2. Convert at the boundary. Only convert to a user's local time when rendering, and only using their real timezone (from browser Intl.DateTimeFormat().resolvedOptions().timeZone, not their UTC offset โ€” offsets change with DST).
  3. Never store an offset. +05:30 doesn't tell you which zone it came from. Store the IANA timezone name (Asia/Kolkata) if you need to reconstruct local time later.

DST is a formatting problem, not a math problem

Adding 24 hours to a timestamp doesn't always land you at the same clock time the next day โ€” DST transitions eat or add an hour. Add "1 day" only via a real date library (date-fns, luxon, Temporal) that understands calendar arithmetic. Adding 86400 seconds is a math operation and gives the wrong answer twice a year.

Leap seconds (mostly) don't exist for you

Unix time deliberately ignores leap seconds โ€” a Unix day is always 86,400 seconds. When a leap second is added, the system clock either slows down or repeats a second. Google's NTP servers "smear" it across the surrounding hours; most systems just have a duplicated second. Unless you're doing financial trading or scientific timing, ignore.

Also: the ITU voted in 2022 to abolish leap seconds by 2035. By the time you next hit a bug, they may be gone entirely.

The "wait, is this local?" checklist

When a timestamp looks wrong:

  1. Count the digits to check the unit.
  2. Look for a Z or offset โ€” if neither, it's ambiguous and probably local.
  3. Check what toString() prints โ€” JavaScript's default Date.toString() renders in local time, which trips up anyone comparing it to a UTC log.
  4. Compare to Date.now() โ€” is it close to the current time? Off by exactly 3600? Off by exactly 5:30? That's your timezone hint.

Timestamp Converter shows all four representations at once โ€” Unix (s/ms), ISO 8601, local, UTC โ€” and a live-updating current timestamp for quick reference.

Common conversions you'll want handy

  • JavaScript ms โ†’ Python s: ms / 1000 (Python's time.time() returns a float).
  • Postgres timestamp โ†’ Unix s: EXTRACT(EPOCH FROM ts).
  • Go time.Time โ†’ Unix ms: t.UnixMilli() (added in Go 1.17).
  • Excel serial date โ†’ Unix s: (serial - 25569) * 86400 (25569 = days between 1900 and 1970).

Related tools:

  • Cron Generator โ€” when the timestamp is a schedule you're trying to build.
  • JSON Formatter โ€” when the timestamps are buried in a JSON payload.

Tools mentioned in this post