Skip to content
LocalOnly
Developer Utilities

Unix Timestamp vs ISO 8601: How to Store Dates

JSON has no date type, so every API picks a format for dates. Here is how Unix timestamps and ISO 8601 strings compare, the bugs each one invites, and what to use where.

Updated October 18, 20263 min readTool runs in your browser

Unix timestamp vs ISO 8601 is a decision every API makes, because JSON has no date type: JSON.stringify turns a Date into a string, and JSON.parse leaves that string a string. The Unix Timestamp Converter converts between the two in the browser, and its page explains seconds, milliseconds and time zones. This guide is about choosing a format for storage and APIs.

Unix timestamp vs ISO 8601 at a glance

Unix seconds        1700000000
Unix milliseconds   1700000000000
ISO 8601, UTC       2023-11-14T22:13:20Z
ISO 8601, offset    2023-11-15T03:43:20+05:30

All four describe the same instant. Unix timestamps are compact and easy to compare and do arithmetic on, but unreadable and ambiguous about their unit. ISO 8601 strings are readable and carry their time zone offset, but are longer and easy to compare wrongly as text.

Bugs that come with Unix timestamps

The classic one is mixing seconds and milliseconds. JavaScript's Date expects milliseconds, while most backends, databases and JWTs use seconds:

new Date(1700000000).toISOString();        // "1970-01-20T16:13:20.000Z"   wrong unit
new Date(1700000000 * 1000).toISOString(); // "2023-11-14T22:13:20.000Z"   correct

A date in January 1970 in your data almost always means seconds were read as milliseconds. Name the unit in the field, as in createdAtMs or expires_at_s, or agree on one unit for the whole API.

Bugs that come with ISO 8601 strings

ISO 8601 strings sort correctly as text only when every value uses the same format and the same offset. With mixed offsets, string order and time order disagree:

["2026-10-18T09:15:00Z", "2026-10-18T10:00:00+02:00"].sort();
// both stay in this order as text, but 10:00+02:00 is 08:00 UTC, which is earlier

Write timestamps in UTC with a Z suffix and fixed precision, and convert to local time only for display. Then sorting and comparing strings gives the right answer.

Time zones in Python

from datetime import datetime, timezone

datetime.fromtimestamp(1700000000)                   # 2023-11-15 03:43:20  local time, no zone
datetime.fromtimestamp(1700000000, tz=timezone.utc)  # 2023-11-14 22:13:20+00:00
datetime.now(timezone.utc).isoformat()               # aware, safe to serialise

Without tz, Python returns a naive datetime in the server's local time, here India's +05:30, with no record of the zone. The same code on a server in another zone produces a different value. datetime.utcnow() is deprecated since Python 3.12 for the same reason; use datetime.now(timezone.utc).

Storing dates in a database

Use the database's date type rather than a number or a string. In PostgreSQL that is timestamptz: it stores an exact instant in UTC and converts input with any offset:

select '2026-10-18 10:00:00+02'::timestamptz at time zone 'UTC';
-- 2026-10-18 08:00:00

Despite its name, timestamptz does not store the original zone, only the instant. If the local time zone matters, such as the zone a meeting was booked in, store it in a separate column.

Which date format to use where

  • JSON APIs: ISO 8601 in UTC, such as 2026-10-18T08:00:00Z. Readable in logs and debuggers, unambiguous, and parsed by every language.
  • Databases: the native type, timestamptz in PostgreSQL.
  • Metrics, events and high-volume logs: Unix milliseconds, where size and fast arithmetic matter and the unit is fixed by the system.
  • Tokens and protocols that specify a format: follow the specification. JWTs, for example, use Unix seconds.

Frequently asked questions

Command Palette

Search for a tool or command