Skip to content
Timekeeping

ISO 8601 Date and Time Format: A Practical Guide

A cheat sheet for ISO 8601: dates, week and ordinal dates, times, UTC offsets, durations and intervals, how RFC 3339 differs, common mistakes, and code examples.

ISO 8601 is the international standard for writing dates and times as text. Its core rule is largest unit first: 2026-10-22 for a date, 14:30:00 for a time, and 2026-10-22T14:30:00Z or 2026-10-22T16:30:00+02:00 for an exact moment. The fixed order and zero-padding make the strings unambiguous across languages and let them sort correctly as plain text.

The standard is published by ISO; the current edition is ISO 8601-1:2019 (with an amendment in 2022), plus ISO 8601-2 for extensions. Most software actually implements RFC 3339, a stricter subset described below.

Calendar dates

FormExampleNotes
Extended2026-10-22year-month-day, the form almost everyone uses
Basic20261022same, without separators
Year and month2026-10reduced precision
Year2026

Four-digit years and two-digit months and days are required: 2026-1-5 is not ISO 8601; 2026-01-05 is.

Week dates and ordinal dates

FormExampleMeaning
Week date2026-W44-3ISO year 2026, week 44, day 3 (Wednesday) = 28 October 2026
Week2026-W44the whole week, Monday 26 October to Sunday 1 November 2026
Ordinal date2026-305the 305th day of 2026 = 1 November 2026

ISO weeks start on Monday (day 1) and end on Sunday (day 7). Week 1 is the week that contains the year’s first Thursday — equivalently, the week containing 4 January. A year therefore has 52 or 53 ISO weeks; 2020 and 2026 have 53, and the next is 2032. The current week is on the week number page.

Ordinal dates count days from 1 January = day 001. They are common in logistics, manufacturing batch codes and some scientific data.

Times

FormExampleNotes
Hours and minutes14:3024-hour clock, always
With seconds14:30:00
Fractional seconds14:30:00.250a comma is also allowed by ISO 8601
Basic format143000
Midnight, start of day00:00
Midnight, end of day24:00removed in the 2019 edition, reinstated by the 2022 amendment

There is no a.m./p.m. in ISO 8601. For converting 12-hour times, see 24-Hour Time and Military Time.

UTC, offsets and combined date-times

FormExampleMeaning
UTC2026-10-22T14:30:00ZZ means zero offset (UTC); military “Zulu”
Positive offset2026-10-22T16:30:00+02:00local time 2 hours ahead of UTC — same instant as above
Negative offset2026-10-22T10:30:00-04:004 hours behind UTC — same instant again
Fractional-hour offset2026-10-22T20:00:00+05:30India — same instant again
No offset2026-10-22T14:30:00local time, zone unspecified
Basic format20261022T143000Z

The T separates date and time. The offset is the local time minus UTC: to get UTC, subtract it (16:30+02:00 → 14:30Z).

Durations and intervals

Durations start with P (“period”). Date components come first; T introduces the time components.

DurationMeaning
P1D1 day
PT2H2 hours
P1DT2H1 day and 2 hours
PT30M30 minutes (note T: P30M is 30 months)
P1Y2M10DT2H30M1 year, 2 months, 10 days, 2 hours, 30 minutes
P2W2 weeks
PT0.5Shalf a second

Intervals join two parts with a slash:

IntervalMeaning
2026-10-22T09:00Z/2026-10-22T17:00Zstart and end
2026-10-22/P3Dstart and duration
PT2H/2026-10-22T12:00Zduration and end
R5/2026-10-22T09:00Z/P1Drepeat 5 times, daily

Calendar durations like P1M are not a fixed number of seconds — a month after 31 January needs a rule — so libraries differ. For date arithmetic, the time calculator does the work.

RFC 3339: the internet profile

RFC 3339 defines a strict subset of ISO 8601 for internet protocols, and most APIs, JSON schemas and logging formats follow it. The main differences:

ISO 8601RFC 3339
Full date and time requiredno (reduced precision allowed)yes: YYYY-MM-DDThh:mm:ss
Offset requirednoyes: Z or ±hh:mm
Basic format (20261022T143000Z)allowednot allowed
Week and ordinal dates, durations, intervalsallowednot covered
Space instead of Tnot in the standard formpermitted “for the sake of readability”
Lower-case t and zallowedallowed, upper case recommended
-00:00 offsetno special meaningmeans “UTC known, local offset unknown”
Leap second 23:59:60allowedallowed

A timestamp like 2026-10-22T14:30:00Z is valid under both.

Why YYYY-MM-DD sorts correctly

Because the units go from largest to smallest and every field has a fixed width, alphabetical order equals chronological order. 2026-09-30 < 2026-10-01 < 2026-10-22 as strings and as dates. 10/22/2026 and 22/10/2026 do not sort, and do not even agree with each other.

The guarantee holds only when all strings use the same form and the same offset. 2026-10-22T23:00:00-05:00 sorts before 2026-10-23T01:00:00Z but is actually three hours later. Normalize to UTC before sorting or comparing as text.

Common mistakes

  • Treating an offset as a time zone. -04:00 says how far a timestamp is from UTC at that instant; it does not say “New York”. New York is −04:00 in summer and −05:00 in winter. If you need future local times to follow daylight saving rules, store the IANA zone name (for example America/New_York) alongside the time.
  • Leaving off the offset. 2026-10-22T10:00 is local time in an unknown zone. In JavaScript, new Date("2026-10-22T10:00") is interpreted in the computer’s own zone, while the date-only new Date("2026-10-22") is interpreted as UTC midnight — two different rules in one function.
  • Mixing the ISO week-year with the calendar year. Around New Year the two differ. Thursday 31 December 2026 is 2026-W53-4, and Friday 1 January 2027 is 2026-W53-5; ISO week 1 of 2027 begins on Monday 4 January 2027. In the other direction, Monday 29 December 2025 is 2026-W01-1. Format patterns make this easy to get wrong: in many libraries YYYY or %G is the week-year and yyyy or %Y is the calendar year.
  • Using P30M for 30 minutes. It means 30 months; minutes need PT30M.
  • Dropping leading zeros. 2026-1-5 or 9:05 are not ISO 8601.

Producing ISO 8601 in code

JavaScript

new Date().toISOString();
// "2026-10-22T14:30:00.000Z"  — always UTC, with milliseconds and Z

toISOString() always converts to UTC. There is no built-in method for a local time with offset or an ISO week number.

Python

from datetime import datetime, timezone

datetime.now(timezone.utc).isoformat()
# '2026-10-22T14:30:00.123456+00:00'

datetime(2026, 10, 22, 14, 30).isoformat()
# '2026-10-22T14:30:00'  — naive: no offset

datetime.fromisoformat("2026-10-22T14:30:00Z")   # accepts 'Z' since Python 3.11
datetime(2027, 1, 1).isocalendar()                # (year=2026, week=53, weekday=5)

Python writes UTC as +00:00, not Z. Use an aware datetime (with tzinfo) whenever the value represents a real instant.

SQL

-- PostgreSQL
SELECT to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"');
SELECT to_char(date '2027-01-01', 'IYYY-"W"IW-ID');   -- 2026-W53-5

-- MySQL
SELECT DATE_FORMAT(UTC_TIMESTAMP(), '%Y-%m-%dT%H:%i:%sZ');

Shell (GNU date)

date -Iseconds                       # 2026-10-22T16:30:00+02:00 (local, with offset)
date -u +%Y-%m-%dT%H:%M:%SZ          # 2026-10-22T14:30:00Z (portable)
date -d 2027-01-01 +%G-W%V-%u        # 2026-W53-5

-I and -d are GNU coreutils options; the explicit +%Y-%m-%dT%H:%M:%SZ format string is the portable choice. For converting between ISO timestamps and seconds since 1970, see Unix Time Explained and the Unix time converter.

Sources

  1. ISO 8601-1:2019 — Date and time — Representations for information interchange
  2. RFC 3339 — Date and Time on the Internet: Timestamps
  3. Python documentation — datetime
  4. MDN — Date.prototype.toISOString()

Dates, offsets and astronomical times quoted here are computed with the same code that powers the site's tools — see data sources and methods. Found an error? Tell us.

More related articles