Dates are written differently around the world — "04/04/26" means April 4 in Japan, April 26 in the US, or even May 4 in Europe depending on convention. ISO 8601 is the international standard that eliminates this ambiguity by defining a single, unambiguous format for dates and times.

This guide covers everything from the basic syntax to timezones, durations, and practical usage in JavaScript, Python, PHP, and SQL.

What is ISO 8601?

ISO 8601 is an international standard published by the International Organization for Standardization (ISO) defining how to represent dates and times. First issued in 1988, the current version is from 2019.

The core design principle is largest-to-smallest ordering: year, then month, then day, then hour, minute, second. This makes ISO 8601 strings naturally sortable alphabetically and removes all geographic ambiguity.

Where ISO 8601 is used

  • REST APIs: JSON datetime fields in API responses
  • Databases: MySQL DATETIME, PostgreSQL TIMESTAMPTZ
  • File names & logs: Sortable timestamps (e.g., 2026-04-04_backup.sql)
  • HTML <time> element: The datetime attribute
  • Calendar apps: iCal (.ics) format
  • Git commits & CI/CD: Standard timestamp format

Basic Format: Dates, Times, and Datetimes

Dates

ISO 8601 dates are always in year-month-day order.

# Extended format (hyphen-separated) — most common
2026-04-04

# Basic format (no separators)
20260404

# Year and month only
2026-04

# Year only
2026

Fields are fixed-width and zero-padded: months and days are always two digits (April → 04).

Times

# Hour:Minute:Second (extended)
14:30:00

# With fractional seconds (period or comma)
14:30:00.500    ← 500 milliseconds
14:30:00,500    ← comma is also valid

# Basic format
143000

Combined Datetime (most important)

Dates and times are combined using the letter T as a separator.

2026-04-04T14:30:00

# With milliseconds
2026-04-04T14:30:00.500

# With timezone (covered in next section)
2026-04-04T14:30:00Z
2026-04-04T14:30:00+09:00

This T-separated format is also used by RFC 3339 (the internet-specific derivative), and is the default output of most programming language datetime functions.

Timezone Notation: Z and ±HH:MM

A datetime without a timezone offset is ambiguous — it only indicates local time without specifying which timezone. For APIs, databases, and cross-system data exchange, always include a timezone designator.

UTC (Coordinated Universal Time)

2026-04-04T14:30:00Z

The trailing Z stands for "Zulu time" and means UTC (offset +00:00).

UTC Offsets

# Japan Standard Time (JST = UTC+9)
2026-04-04T23:30:00+09:00

# US Eastern Daylight Time (EDT = UTC-4)
2026-04-04T10:30:00-04:00

# India Standard Time (IST = UTC+5:30)
2026-04-04T20:00:00+05:30

The offset like +09:00 means "this time is 9 hours ahead of UTC."

Z vs +00:00

Both represent the same instant in time, but conventions differ:

  • Z: Common in API responses, logs, and system communication — concise and unambiguous
  • +00:00: Sometimes used when specifically referring to London time (no daylight saving)

JavaScript's Date.toISOString() outputs Z by default.

Week Numbers & Ordinal Dates

ISO Week Date

# Format: YYYY-Www-D (W = Week, D = day of week: 1=Mon, 7=Sun)
2026-W14-6    ← Saturday of week 14, 2026

# Week only
2026-W14

ISO weeks start on Monday. Week 1 (W01) is defined as the week containing the first Thursday of the year. This means January 1st might belong to the last week of the previous year.

Ordinal Dates

# Format: YYYY-DDD (DDD = day of year)
2026-094    ← 94th day of 2026 (= April 4)

Useful in log processing, astronomical calculations, or any context where "day of year" is more natural than month/day.

Durations

ISO 8601 also standardizes how to express lengths of time. Duration strings start with P (for "Period").

# General syntax
P[nY][nM][nW][nD]T[nH][nM][nS]

# Examples
P1Y           ← 1 year
P3M           ← 3 months
P7D           ← 7 days
PT2H30M       ← 2 hours 30 minutes
P1Y2M3DT4H5M  ← 1 year 2 months 3 days 4 hours 5 minutes
PT30S         ← 30 seconds

The T separates date components (Y/M/W/D) from time components (H/M/S). It's required when any time component is present.

Real-world usage

  • JWT expiration: PT1H (1 hour)
  • Cache TTL: PT5M (5 minutes)
  • HTML <video> duration attribute: PT1M30S (1 minute 30 seconds)
  • iCal DURATION property: P1D (1 day)

Intervals and Repeating Intervals

Time Intervals

# Start/End
2026-04-01T00:00:00Z/2026-04-30T23:59:59Z

# Start/Duration
2026-04-01T00:00:00Z/P1M

# Duration/End
P1M/2026-04-30T23:59:59Z

Repeating Intervals

# Format: R[n]/[interval]
R5/2026-04-04T09:00:00Z/PT1H   ← 5 times, every hour from 09:00 UTC
R/2026-04-04T09:00:00Z/P1W     ← repeat weekly forever (R alone = infinite)

ISO 8601 in Programming Languages

JavaScript / TypeScript

// Get current datetime as ISO 8601 (UTC)
const now = new Date().toISOString();
// → "2026-04-04T14:30:00.000Z"

// Parse an ISO 8601 string
const date = new Date("2026-04-04T14:30:00+09:00");

// Format for display using Intl.DateTimeFormat
const formatter = new Intl.DateTimeFormat('en-US', {
  year: 'numeric', month: '2-digit', day: '2-digit',
  hour: '2-digit', minute: '2-digit', second: '2-digit',
  timeZone: 'Asia/Tokyo'
});
console.log(formatter.format(date));

Python

from datetime import datetime, timezone, timedelta

# Current UTC time in ISO 8601
now_utc = datetime.now(timezone.utc)
print(now_utc.isoformat())
# → "2026-04-04T14:30:00.000000+00:00"

# With JST offset
jst = timezone(timedelta(hours=9))
now_jst = datetime.now(jst)
print(now_jst.isoformat())
# → "2026-04-04T23:30:00.000000+09:00"

# Parse ISO 8601 (Python 3.7+)
dt = datetime.fromisoformat("2026-04-04T14:30:00+09:00")

# Z suffix supported in Python 3.11+
dt = datetime.fromisoformat("2026-04-04T14:30:00Z")

PHP

format(DateTime::ATOM);
// → "2026-04-04T14:30:00+00:00"

// Parse ISO 8601
$dt = new DateTime("2026-04-04T14:30:00+09:00");

// Carbon (common in Laravel)
$now = Carbon\Carbon::now('Asia/Tokyo')->toIso8601String();
?>

SQL (MySQL / PostgreSQL)

-- MySQL: format current datetime as ISO 8601
SELECT DATE_FORMAT(NOW(), '%Y-%m-%dT%H:%i:%sZ') AS iso8601;

-- PostgreSQL: ISO 8601 with timezone
SELECT NOW()::timestamptz AT TIME ZONE 'UTC';
-- or
SELECT to_char(NOW() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"');

ISO 8601 in HTML: The <time> Element

HTML5's <time> element lets you embed machine-readable datetimes in your markup using the datetime attribute. This helps search engines, screen readers, and other tools interpret dates correctly.

<!-- Date only -->
<time datetime="2026-04-04">April 4, 2026</time>

<!-- Full datetime with timezone -->
<time datetime="2026-04-04T14:30:00+09:00">April 4, 2026 at 2:30 PM JST</time>

<!-- Blog article publish date -->
<article>
  <h1>Article Title</h1>
  <p>Published: <time datetime="2026-04-04" pubdate>April 4, 2026</time></p>
</article>

Google's structured data (Schema.org) also recommends ISO 8601 for date fields:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "datePublished": "2026-04-04T09:00:00+09:00",
  "dateModified": "2026-04-04T12:00:00+09:00"
}
</script>

Common Mistakes to Avoid

1. Missing timezone

# Ambiguous — which timezone is 14:30?
2026-04-04T14:30:00

# Clear — UTC
2026-04-04T14:30:00Z

# Clear — JST
2026-04-04T14:30:00+09:00

Always include a timezone offset in API responses and stored data. Omitting it is a common source of off-by-hours bugs when servers are in different timezones.

2. Wrong separators

# Not ISO 8601
2026/04/04 14:30:00

# Correct
2026-04-04T14:30:00

3. Wrong order (US-style)

# Wrong
04-04-2026

# Correct (largest unit first)
2026-04-04

4. Missing zero-padding

# Wrong
2026-4-4

# Correct
2026-04-04

FAQ

Q. What's the difference between ISO 8601 and RFC 3339?

RFC 3339 is a stricter subset of ISO 8601 designed for internet protocols. Key differences: RFC 3339 requires a timezone designator (no omitting it), doesn't allow a space in place of T, and restricts some edge cases. In practice, most APIs labeled "ISO 8601" actually mean RFC 3339 format. The two are interchangeable for everyday use.

Q. Does JavaScript's Date object fully support ISO 8601?

Mostly yes, but with a gotcha: date-only strings like 2026-04-04 are parsed as UTC midnight by most browsers, not local midnight. To avoid surprises, always use the full datetime form 2026-04-04T00:00:00 when parsing, or use a library like date-fns, Day.js, or Luxon.

Q. Is Z the same as +00:00?

Yes — both represent UTC. Z is simply a shorthand notation. Some strict parsers accept only one form, so check your target environment. Most modern parsers handle both.

Q. How do I quickly convert between date formats?

Use Devryo's Date Format Converter to instantly convert between ISO 8601, RFC 2822, Unix timestamps, and 9 other formats. No login required.

Summary

ISO 8601 is the universal language of dates and times in software. The key rules to remember:

  • Format: YYYY-MM-DDTHH:mm:ss — T separator, zero-padded fields
  • Timezone: Always include Z or ±HH:MM in cross-system data
  • Order: Year → Month → Day → Hour → Minute → Second (largest first)

Need to convert date formats? Try the Date Format Converter or Unix Timestamp Converter — both free, no login needed.