What does an ISO 8601 date look like?
ISO 8601 Date Format Explained
An ISO 8601 date looks like 2026-09-26: four-digit year, two-digit month, two-digit day, largest unit first, separated by hyphens. A full timestamp adds a T, the time and an offset from UTC: 2026-09-26T14:05:00+05:30, or 2026-09-26T08:35:00Z where Z means UTC itself. That is the form almost everyone means by "ISO format", and it is the one to use for APIs, logs and file names. The standard itself is much larger. It also defines week dates, ordinal dates, a compact "basic" format without separators, reduced precision, decimal fractions, durations and intervals, and most of those variants are not accepted by most parsers.
Why the format works
Three design decisions make ISO 8601 the right default for machine-readable dates:
- Largest unit first.
2026-09-26cannot be misread as 9 February or 26 September depending on the reader's country, which09/02/2026can. - Fixed width, zero padded. Strings sort lexicographically in chronological order, provided they share the same offset. That is why
2026-09-26_backup.sqlbeats26-9-2026_backup.sqlas a file name. - Explicit offset. A timestamp with
Zor+05:30identifies one instant. Without it, the reader has to guess the zone.
Anatomy of a timestamp
2026-09-26T14:05:00.123+05:30
│ │ │ ││ │ │ │ └───── UTC offset: +hh:mm, or Z for UTC
│ │ │ ││ │ │ └───────── decimal fraction of the second (. or ,)
│ │ │ ││ │ └─────────── second, 00–59 (60 during a leap second)
│ │ │ ││ └────────────── minute, 00–59
│ │ │ │└───────────────── hour, 00–23
│ │ │ └────────────────── T separates date from time
│ │ └──────────────────── day, 01–31
│ └─────────────────────── month, 01–12
└──────────────────────────── year, four digits (0000–9999)Enter this timestamp into the Date Formatter and it will render it in any pattern and any zone:
2026-09-26T14:05:00+05:30With the default pattern yyyy-MM-dd'T'HH:mm:ssxxx, the output depends on the zone you choose, which is the point: the instant is fixed and only its representation changes.
| Zone | Output |
|---|---|
| Asia/Kolkata | 2026-09-26T14:05:00+05:30 |
| UTC | 2026-09-26T08:35:00+00:00 |
| America/New_York | 2026-09-26T04:35:00-04:00 |
All three strings denote the same moment. Note that +00:00 and Z are equivalent; many serialisers emit Z, and the Date Formatter's pattern token xxx emits +00:00. Use XXX if you want Z.
Every variant in one table
| Variant | Extended format | Basic format | RFC 3339 | Notes |
|---|---|---|---|---|
| Calendar date | 2026-09-26 |
20260926 |
Yes (extended only) | The common case |
| Reduced precision | 2026-09, 2026 |
2026 |
No | 202609 is not allowed: it would look like YYMMDD |
| Week date | 2026-W39-6 |
2026W396 |
No | ISO week-numbering year, week 01–53, weekday 1 (Monday) to 7 |
| Ordinal date | 2026-269 |
2026269 |
No | Day of year, 001–366 |
| Time | 14:05:00, 14:05 |
140500, 1405 |
Seconds required | |
| Decimal fraction | 14:05:00.5, 14:05:00,5 |
140500,5 |
Dot only | ISO historically preferred the comma; fractions apply to the smallest unit present, so 14:05,5 is 14:05:30 |
| UTC | 14:05:00Z |
140500Z |
Yes (Z or z) |
|
| Offset | +05:30, +05 |
+0530 |
±hh:mm only |
|
| Date and time | 2026-09-26T14:05:00+05:30 |
20260926T140500+0530 |
Yes | RFC 3339 also allows a space or lowercase t |
| Duration | P1DT2H30M15S |
same | No (appendix only) | |
| Interval | 2026-09-26T09:00Z/2026-09-26T17:30Z |
same | No | Also start/duration and duration/end |
| Repeating interval | R5/2026-09-26T09:00Z/P1D |
same | No | Five daily repetitions |
The same date written three ways: 2026-09-26 is Saturday of ISO week 39, and the 269th day of the year. The Date Formatter produces the week form with the pattern RRRR-'W'II-i (output 2026-W39-6) and the ordinal form with yyyy-DDD (output 2026-269).
Week dates and the week-numbering year
ISO weeks start on Monday, and week 01 is the week containing the year's first Thursday (equivalently, the week containing 4 January). So the first days of January can belong to the last week of the previous year, and the last days of December to week 01 of the next. That "week-numbering year" is a separate field from the calendar year, and confusing the two is the cause of the YYYY formatting bug covered in date format patterns. Years with 53 ISO weeks are those that start on a Thursday, or leap years that start on a Wednesday; 2026 is one of them.
Durations
A duration is written P, then date components, then T, then time components:
P1Y2M10DT2H30M15S 1 year, 2 months, 10 days, 2 hours, 30 minutes, 15 seconds
P2W 2 weeks
PT36H 36 hours
P1M 1 month
PT1M 1 minuteThe T is what distinguishes months from minutes, so P1M and PT1M differ by a factor of about 43,800. Only the smallest component may carry a fraction (PT0.5S, P1.5D). Try one in the Duration Formatter:
P1DT2H30M15SIt reads 1 day, 2 hours, 30 minutes, 15 seconds and totals 95,415 seconds. Two warnings apply to every duration library:
- Years and months have no fixed length.
P1Madded to 31 January gives a different number of days than added to 1 February. Converting to seconds requires an average (the Duration Formatter uses 365.2425 days per year and 30.44 days per month, and says so). - Days are not always 24 hours. Across a daylight-saving transition,
P1DandPT24Hland on different wall-clock times. Java models this split explicitly:Periodholds years, months and days;Durationholds exact seconds, andDuration.parse("P1DT2H30M15S")prints back asPT26H30M15S, whileDuration.parse("P1M")throws.
ISO 8601 vs RFC 3339
RFC 3339 is a profile of ISO 8601 for internet protocols. It picks one unambiguous subset and adds two small extensions. JSON Schema's date-time format, most API style guides and many log formats reference RFC 3339, not ISO 8601.
| ISO 8601 | RFC 3339 | |
|---|---|---|
| Separator between date and time | T (omission allowed by agreement in older editions) |
T, t, or a space "for readability" |
| Seconds | Optional | Required |
| Offset | Optional (a time without one is local time) | Required |
| Offset forms | Z, ±hh:mm, ±hhmm, ±hh |
Z or ±hh:mm only |
-00:00 |
Not given a distinct meaning | Means "time is in UTC, local offset unknown" |
| Basic format, week and ordinal dates | Yes | No |
Leap second :60 |
Yes | Yes |
The practical intersection, YYYY-MM-DDTHH:MM:SS[.fff](Z|±HH:MM), is valid under both. Emit exactly that and you will not need to know which one a consumer implements.
How languages parse it
| Input | JavaScript Date |
Python 3.11+ fromisoformat |
Java java.time |
|---|---|---|---|
2026-09-26 |
Midnight UTC | Naive midnight | LocalDate.parse |
2026-09-26T00:00 |
Midnight local | Naive midnight | LocalDateTime.parse |
2026-09-26T14:05:00Z |
Parsed | Parsed (from 3.11; earlier versions reject Z) |
Instant.parse |
2026-09-26T14:05:00+05:30 |
Parsed | Parsed | OffsetDateTime.parse; Instant.parse since Java 12 |
20260926T140500+0530 |
Invalid Date | Parsed | Needs a custom pattern (BASIC_ISO_DATE covers the date part only) |
2026-W39-6 |
Invalid Date | Parsed | DateTimeFormatter.ISO_WEEK_DATE |
2026-269 |
Invalid Date | Rejected | DateTimeFormatter.ISO_ORDINAL_DATE |
Comma fraction 2026-09-26T14:05:00,5+05:30 |
Invalid Date | Parsed | Needs a custom pattern |
The first two rows are the most common JavaScript date bug. The ECMAScript specification says a date-only ISO string is UTC but a date-time without an offset is local time. In India, new Date("2026-09-26") is 05:30 local time on the 26th, while new Date("2026-09-26T00:00") is 18:30 UTC on the 25th. In the Americas, the date-only form displays as the previous day. If you mean a calendar date with no time, keep it as a string or a date-only type; if you mean an instant, include the offset.
Mistakes that produce valid-looking but wrong strings
- A literal
Zon a local time. Patterns such asyyyy-MM-dd'T'HH:mm:ss'Z'print the letter Z whatever the value's zone is. If the value is local time, the string claims to be UTC and is off by the local offset. Use an offset token (XXXin date-fns and Java,%zin Python) or convert to UTC first. JavaScript'stoISOString()is safe because it always converts to UTC. - Missing zero padding.
2026-9-26is not ISO 8601, will not sort correctly, and is rejected by strict parsers. - An offset is not a time zone.
+05:30records the offset at one instant. It says nothing about daylight-saving rules, so it cannot tell you the offset of the same wall-clock time next month. For future events in local time (a meeting at 09:00 in New York every Monday), store the local time and the IANA zone name, and compute the offset when needed. - Two-digit years and implied centuries. ISO 8601 no longer allows two-digit years in its general forms; always write four digits.
Rules for using ISO 8601 in systems
- Serialise instants as RFC 3339 with an explicit offset, preferably
Zfor stored and logged values. - Use calendar dates (
2026-09-26) for date-only values such as birthdays and due dates, and never attach a time or zone to them. - Include fractional seconds only when you need them, and document the precision; JavaScript keeps milliseconds, Python microseconds, Java and PostgreSQL up to nanoseconds and microseconds respectively.
- Do not assume other variants will parse. Week dates, ordinal dates, basic format and comma fractions are valid ISO 8601 and are rejected by common parsers.
- For stored numeric instants, see Unix timestamps; to convert an ISO string to epoch seconds, use the Unix Timestamp Converter.