Parse an ISO 8601 date string
Take a string like `2026-05-16T14:23:00Z` and convert it to a typed date object — for filtering logs by time, computing age, or feeding into date arithmetic.
How to parse an iso 8601 date string in each shell
date -d "2026-05-16T14:23:00Z" +%sGNU only. The natural-language parser accepts most ISO 8601 forms (`Z` UTC, `+02:00` offset, `T` separator or space). Output via `+FORMAT`: `+%s` for epoch, `+%Y-%m-%d` to reformat, etc.
date -d "2026-05-16T14:23:00Z" +%sdate -d "2026-05-16T14:23:00Z" +%s[DateTimeOffset]::Parse("2026-05-16T14:23:00Z")Strict-mode: `[DateTimeOffset]::ParseExact("2026-05-16T14:23:00Z", "yyyy-MM-ddTHH:mm:ssZ", $null)`. Try-parse for untrusted input: `[DateTimeOffset]::TryParse($s, [ref]$out)` returns bool, never throws.
powershell -NoProfile -Command "[DateTimeOffset]::Parse('2026-05-16T14:23:00Z')"cmd has no native date parser. Even if it did, `set d=2026-05-16` then arithmetic via `set /a` only handles integers, not date semantics. Always shell out.
Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.
Gotchas & notes
- **GNU vs BSD divergence**: GNU `date -d "2026-05-16T14:23:00Z" +%s` parses essentially any ISO 8601 variant — `Z`, `+HH:MM`, microseconds, missing seconds, etc. BSD / macOS `date` does NOT have `-d`; you need `date -j -f "%Y-%m-%dT%H:%M:%SZ" "2026-05-16T14:23:00Z" +%s`. The `-j` means "don't actually try to set the system clock from the input" (a historical BSD legacy where `date` was both reader and writer); the `-f` specifies the input format which **MUST exactly match** the input string — no flexibility, no auto-detection. If your input has fractional seconds, the format string needs `%S` (BSD doesn't support `%N`) — so you preprocess: `sed 's/\.[0-9]*//' input`.
- Timezone parsing across the divergence: GNU `date -d "2026-05-16T14:23:00+02:00" +%s` correctly normalizes to UTC epoch. BSD `date -j -f "%Y-%m-%dT%H:%M:%S%z" "2026-05-16T14:23:00+0200" +%s` works BUT only if the offset is `+HHMM` (no colon — `+0200`, not `+02:00`). The ISO 8601 standard allows both; BSD `%z` only accepts the no-colon variant. Strip the colon first: `echo "$iso" | sed 's/\([+-][0-9][0-9]\):\([0-9][0-9]\)$/\1\2/'` before piping to BSD `date`. Or `brew install coreutils` and use `gdate`.
- pwsh `[DateTimeOffset]::Parse($s)` is locale-sensitive by DEFAULT — same string `2026-05-16` is `May 16` in `en-US` and `Apr 06` in some Asian locales (which interpret `MM` differently). For machine-readable ISO input, always pass `[CultureInfo]::InvariantCulture`: `[DateTimeOffset]::Parse($s, [CultureInfo]::InvariantCulture, [DateTimeStyles]::AssumeUniversal)`. The `AssumeUniversal` flag treats unzoned strings as UTC instead of LOCAL (the default — silently wrong for log-correlation). For untrusted input, use `TryParse` to avoid exception-driven control flow: `if ([DateTimeOffset]::TryParse($s, [ref]$dto)) { ... }`.
- Common parse failures: (1) `2026-05-16` (date only) parses as `2026-05-16T00:00:00` LOCAL on pwsh — use `AssumeUniversal` to force UTC. (2) `2026-05-16T14:23` (no seconds) — GNU accepts; pwsh `Parse` accepts; BSD `date -j -f "%Y-%m-%dT%H:%M"` accepts. (3) `20260516T142300Z` (basic format, no separators) — GNU GNU `date -d` rejects; BSD `date -j -f "%Y%m%dT%H%M%SZ"` accepts; pwsh rejects unless you use `ParseExact` with the explicit format. (4) Fractional seconds beyond microseconds — pwsh `[DateTime]` only stores 100 ns ticks, so nanosecond input loses two digits silently. For full precision use `[DateTimeOffset]` (same precision but at least preserves offset) or store as ISO string + epoch_ns int side-by-side.
Related commands
Related tasks
- Format the current date as ISO 8601— Emit `YYYY-MM-DDTHH:MM:SS±HH:MM` (or the UTC `…Z` form) — the format every machine-readable log, JSON API, and database column should agree on.
- Convert a Unix epoch to a human-readable date— Render a Unix-epoch integer (e.g. `1747396980`) as a readable date — for log inspection, file-metadata audits, and translating database timestamps.
- Get the current timestamp— Print the current date / time as either a Unix epoch (seconds since 1970-01-01 UTC) or an ISO 8601 string — for log lines, filenames, expiry calculations, and HTTP `Date` headers.