Back to Blog
Reference 2026-04-24

Timestamps and ISO 8601 Explained

How to handle dates and times across systems without timezone disasters.

Timezone bugs cost engineering teams thousands of hours per year. The fix is consistent representation, and ISO 8601 is the standard.

ISO 8601 Format

2026-04-30T15:32:18Z          UTC

2026-04-30T15:32:18+09:00 With offset

2026-04-30T15:32:18.123Z With ms

20260430T153218Z Compact (avoid)

The T separates date and time. Z means Zulu = UTC. Always use the extended form with hyphens and colons.

Unix Timestamps

1745939938        seconds since 1970-01-01 UTC

1745939938123 milliseconds (JavaScript)

1745939938123456 microseconds (databases)

Unix time is timezone-free by definition — it counts seconds, not clock ticks. Display in any zone afterward.

The Three Sins

1. Storing local time without offset: 2026-04-30 15:32:18 is ambiguous.

2. Mixing local and UTC: pick one for storage; convert at the edges.

3. Trusting client clocks: laptops drift; assume the server clock is truth.

Storing Times

  • Database: TIMESTAMP WITH TIME ZONE (Postgres) or BIGINT for Unix ms (cross-DB).
  • JSON: ISO 8601 string with explicit offset or Z.
  • Logs: ISO 8601 with milliseconds, always Zulu.

Date-Only vs Datetime

For dates without times (birthdays, holidays), store as plain YYYY-MM-DD and never apply timezone. Adding a default time of midnight UTC has caused January 1 to display as December 31 in negative offsets too many times to count.

Time Math

Use a library: date-fns, Luxon, day.js. Native Date arithmetic is full of edge cases (DST transitions, month boundaries).

Display

Convert to user's local timezone in the UI layer, never in storage. Use Intl.DateTimeFormat for locale-aware rendering:

new Intl.DateTimeFormat('ko-KR', { dateStyle: 'long', timeStyle: 'short' }).format(date);

For converting between formats see the [Timestamp Converter](https://sdk.is/timestamp-converter).