ISO 8601 is the international standard for representing dates and times. Every developer has heard of it. Far fewer have actually read it.
The result: code that parses 2026-03-24T08:00:00Z correctly but quietly breaks on 2026-03-24T08:00:00+00:00. Or assumes that ISO 8601 date strings are always sortable. Or mixes up T08:00:00 and T080000.
Let's close the gaps.
The Formats You Actually Need to Know
Date Only
2026-03-24 ← Extended format (with hyphens) — most common
20260324 ← Basic format (no hyphens) — valid ISO, rare in APIs
2026-W12-2 ← Week date: year-W{week}-{day-of-week} (1=Mon, 7=Sun)
2026-083 ← Ordinal date: year-{day-of-year}
Date and Time
2026-03-24T08:00:00 ← Local time (no offset — timezone unknown)
2026-03-24T08:00:00Z ← UTC (Z = +00:00)
2026-03-24T08:00:00+05:30 ← UTC+5:30 (India)
2026-03-24T08:00:00+0530 ← Also valid: colon in offset is optional
2026-03-24T08:00:00.000Z ← With milliseconds
2026-03-24T08:00:00.000000Z ← With microseconds
What Many Developers Get Wrong: Z ≠ +00:00 (In Practice)
Technically, Z and +00:00 represent the same UTC offset. But in practice, parsers sometimes treat them differently:
// Chrome/V8
new Date('2026-03-24T08:00:00Z').toISOString(); // "2026-03-24T08:00:00.000Z" ✓
new Date('2026-03-24T08:00:00+00:00').toISOString(); // "2026-03-24T08:00:00.000Z" ✓
// Some older Java DateTimeFormatter configurations reject Z without explicit format
// Some older .NET code only handles one or the other
// PostgreSQL: both work. MySQL: both work. SQLite: it depends on the version.
If you control the format, always use Z. It's shorter and more widely supported.
The Sortability Trap
ISO 8601 datetime strings are lexicographically sortable — if they all use the same offset:
const dates = [
'2026-03-24T10:00:00Z',
'2026-03-24T08:00:00+05:30', // same instant as 02:30 UTC
'2026-03-24T06:00:00-02:00', // same instant as 08:00 UTC
];
dates.sort(); // Lexicographic sort
// Result: ['2026-03-24T06:00:00-02:00', '2026-03-24T08:00:00+05:30', '2026-03-24T10:00:00Z']
// The "earliest" is actually 08:00 UTC — sorted last!
For reliable sorting: always normalize to UTC before storing or sorting. A lexicographic sort on *Z strings is correct. A lexicographic sort on mixed-offset strings is wrong.
Duration Format
ISO 8601 also defines a duration format that almost no one learns until they encounter it in an API response:
P1Y2M3DT4H5M6S = 1 year, 2 months, 3 days, 4 hours, 5 minutes, 6 seconds
P30D = 30 days
PT2H30M = 2 hours 30 minutes
P1W = 1 week
The P prefix stands for "period." The T separates date components (Y, M, D) from time components (H, M, S).
Used by: RSS/Atom feeds (<itunes:duration>), YouTube API video durations, HTML <time> element, PostgreSQL INTERVAL type.
// Parsing ISO 8601 duration in JS (no built-in support)
function parseDuration(iso) {
const match = iso.match(/P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?/);
return {
years: parseInt(match[1] || 0),
months: parseInt(match[2] || 0),
days: parseInt(match[3] || 0),
hours: parseInt(match[4] || 0),
minutes: parseInt(match[5] || 0),
seconds: parseInt(match[6] || 0),
};
}
parseDuration('P1Y2M3DT4H5M6S');
// { years: 1, months: 2, days: 3, hours: 4, minutes: 5, seconds: 6 }
Interval Format
ISO 8601 intervals define a time range. Three forms:
2026-01-01/2026-03-24 ← Start/End
2026-01-01/P83D ← Start/Duration
P83D/2026-03-24 ← Duration/End
Not widely implemented in mainstream languages, but you'll see it in geospatial APIs (OGC standards) and some scheduling systems.
What to Actually Use in APIs
For any API you build or consume:
✓ Use: 2026-03-24T08:00:00.000Z (UTC, milliseconds, Z suffix)
✓ Use: 2026-03-24 (date only, no time component)
✗ Avoid: 2026-03-24T08:00:00 (ambiguous — local or UTC?)
✗ Avoid: 03/24/2026 (US format, not ISO)
✗ Avoid: March 24, 2026 (human-readable, not parseable)
✗ Avoid: 24-03-2026 (looks like ISO but isn't)
JSON Schema Date Validation
If you're validating ISO dates in JSON Schema:
{
"type": "string",
"format": "date" // validates YYYY-MM-DD
}
{
"type": "string",
"format": "date-time" // validates YYYY-MM-DDTHH:MM:SSZ
}
JSON Schema format validation is optional in most validators — don't rely on it for security; always validate explicitly in your application code.
Quick Sanity Check
When debugging an unfamiliar timestamp from an API, datetimecalculator.app/unix-timestamp will parse ISO 8601 strings and show you the UTC and local interpretations — useful for telling whether that +05:30 offset was applied correctly.
Summary
- Extended format (hyphens/colons) is standard for APIs; basic format is valid ISO but rare
- Local time strings (no Z, no offset) are ISO 8601 — but they're ambiguous in distributed systems
- Always normalize to UTC for storage and sorting
- Learn ISO 8601 durations — you'll encounter them sooner or later
- Pair
%G(ISO week-year) with%V(ISO week number), not%Y
What's the most unexpected place you've encountered ISO 8601 format requirements? I once found it buried in a hardware sensor protocol spec.
Top comments (0)