Skip to content
shellmap

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

Bashunix
date -d "2026-05-16T14:23:00Z" +%s

GNU 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.

Zshunix
date -d "2026-05-16T14:23:00Z" +%s
Fishunix
date -d "2026-05-16T14:23:00Z" +%s
PowerShellwindows
[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.

cmd.exewindows
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