ISO 8601 and RFC 3339 formats
The exact syntax for dates, times, offsets and fractions, what the Z suffix means, how to write durations and intervals, and why interchange should use these formats and nothing else.
The pieces of a timestamp
2026-09-18 date only
10:30:00 time, no zone
2026-09-18T10:30:00Z UTC (Z means the same as +00:00)
2026-09-18T10:30:00+02:00 offset from UTC
2026-09-18T10:30:00.123Z fractional seconds
2026-09-18T10:30:00.123456789Z nanoseconds
2026-09-18T10:30:00+02:00[Europe/Paris] offset plus IANA zone (RFC 9557)
2026-W38-5 ISO week date
2026-261 ordinal date: day 261 of 2026- The separator is
Tbetween date and time; lowercasetis allowed by the standard but rarely accepted by parsers. Zand+00:00mean the same instant. Pick one —Zis shorter and conventional for UTC.- Fractional seconds use a dot, not a comma, and any number of digits is valid.
- An offset of
-00:00has a specific meaning in RFC 3339: the time is UTC but the local offset is unknown.
Durations, intervals and recurrence
| Form | Meaning | Example |
|---|---|---|
| PnYnMnDTnHnMnS | Duration | P1Y2M3DT4H5M6S |
| PnW | Weeks | P2W (same as P14D) |
| start/end | Interval | 2026-09-18T00:00Z/2026-09-19T00:00Z |
| start/duration | Interval | 2026-09-18T00:00Z/P1D |
| R[n]/start/duration | Recurring | R5/2026-09-18T09:00Z/P1D |
| R/start/duration | Unbounded repeat | R/2026-09-18T09:00Z/P1W |
// JavaScript has no duration parser; Temporal does (shipping in modern runtimes)
const d = Temporal.Duration.from("P1Y2M3DT4H5M6S");
const later = Temporal.PlainDate.from("2026-01-31").add({ months: 1 });
later.toString(); // "2026-02-28" — clamped, not overflowing into MarchThe T is required when a duration has a time part, because P1M is ambiguous otherwise: M before the T is months, after it is minutes.
Why this and not something else
- It sorts correctly as plain text, so string comparison equals chronological comparison for equal offsets.
- It is unambiguous: no one has to guess whether
03/04is March or April. - It includes the offset, which a local format like
18/09/2026 10:30cannot express. - Every mainstream language parses it out of the box.
# RFC 3339 requires an uppercase T and Z, and a fixed-width offset
date -u +%Y-%m-%dT%H:%M:%SZ
# 2026-09-18T10:30:00Z
# GNU date can round-trip an offset into a zone
TZ=Europe/Paris date -d '2026-09-18T10:30:00+02:00' +%Y-%m-%dT%H:%M:%S%:z⚠️
RFC 3339 permits a wider offset range than ISO 8601, and ISO 8601 permits forms RFC 3339 forbids (a comma for fractions, an offset without a colon). Choose RFC 3339 for protocols: it is a strict subset that every parser agrees on.
FAQ
Should I store nanoseconds?
Only if you need them. Databases commonly truncate to microseconds or milliseconds, so a nanosecond-precision input will not round-trip. Decide the precision and document it.
What does the Z mean?
It is the zone designator for UTC, from the military convention of calling UTC Zulu time. It is equivalent to an offset of
+00:00.Related
Parsing and formatting dates safely Calendars, leap years and leap seconds
Last refreshed 2026-09-18.