datetime.fromisoformat / isoformat

The machine-readable pair. isoformat() writes 2026-09-29T14:30:00+02:00, fromisoformat() reads it back unchanged — and since Python 3.11 it also reads Z, basic formats like 20260929T1430 and ISO week dates.

datetime methodPython 3.7+ (full ISO 8601 since 3.11)Live demo
Common call
datetime.fromisoformat('2026-09-29T14:30Z') · dt.isoformat()
Returns
datetime (aware if the text has an offset) · str
Replaces
strptime(s, '%Y-%m-%dT%H:%M:%S%z') and hand-written ISO formatting
Watch out
Before 3.11 fromisoformat rejected Z and most non-isoformat() text
datetime.fromisoformat(date_stringdate_string — ISO 8601 text. date: YYYY-MM-DD, YYYYMMDD, YYYY-Www[-D]. time: HH[:MM[:SS[.ffffff]]] plus an optional offset or Z. datetime: a date, any ONE separator character, a time.type: str · required)
→ datetime

Demo

Live evaluation
Type ISO 8601 text. Offsets become a timezone, Z becomes UTC, missing parts become zero.
Try:
Inputs
textstrISO 8601 text
Code
from datetime import datetime
datetime.fromisoformat('2026-09-29T14:30:05.123+02:00')
Result
datetime.datetime(2026, 9, 29, 14, 30, 5, 123000, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200)))

fromisoformat validates twice: the text must be ISO 8601 ("Invalid isoformat string"), and the numbers must make a real date ("day is out of range for month" for 30 February). isoformat never rounds: 14:30:59.999999 with timespec="minutes" is 14:30. UTC is written +00:00, not Z — fromisoformat accepts both.

Parameters

NameTypeRequiredDescription
date_stringstryesISO 8601 text. date: YYYY-MM-DD, YYYYMMDD, YYYY-Www[-D]. time: HH[:MM[:SS[.ffffff]]] plus an optional offset or Z. datetime: a date, any ONE separator character, a time.
sepstrno ('T')isoformat() on datetime only: the single character between date and time.
timespecstrno ('auto')isoformat(): 'auto', 'hours', 'minutes', 'seconds', 'milliseconds' or 'microseconds'. Extra digits are truncated, not rounded.

Return value

datetime — fromisoformat: a new date / time / datetime (aware when the text has an offset or Z). isoformat: a str.

Common patterns

datetime to JSON and back
json cannot serialize datetime; ISO text round-trips exactly.
import json
from datetime import datetime
payload = json.dumps({'at': dt.isoformat()})
at = datetime.fromisoformat(json.loads(payload)['at'])
Write Z instead of +00:00
Some APIs insist on the Z suffix; isoformat never writes it.
stamp = dt.astimezone(UTC).isoformat().replace('+00:00', 'Z')
Accept a string or a date
date.fromisoformat for input fields; keep the error message for the user.
from datetime import date
try:
    due = date.fromisoformat(form['due'])
except ValueError as e:
    errors['due'] = str(e)

Examples

1. Offset → timezone
from datetime import datetime datetime.fromisoformat('2026-09-29T14:30:05.123+02:00')
Returns
datetime.datetime(2026, 9, 29, 14, 30, 5, 123000, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200)))
2. Z means UTC (3.11+)
from datetime import datetime datetime.fromisoformat('20260929T143005Z')
Returns
datetime.datetime(2026, 9, 29, 14, 30, 5, tzinfo=datetime.timezone.utc)
3. Comma as decimal mark
from datetime import datetime datetime.fromisoformat('2026-09-29 14:30:05,5')
Returns
datetime.datetime(2026, 9, 29, 14, 30, 5, 500000)
4. ISO week date
from datetime import date date.fromisoformat('2026-W40')
Returns
datetime.date(2026, 9, 28)
5. time with a leading T
from datetime import time time.fromisoformat('T143005.5+0530')
Returns
datetime.time(14, 30, 5, 500000, tzinfo=datetime.timezone(datetime.timedelta(seconds=19800)))
6. isoformat with timespec
from datetime import datetime datetime(2026, 9, 29, 14, 30, 5, 123456).isoformat(timespec='milliseconds')
Returns
'2026-09-29T14:30:05.123'
7. str() is isoformat with a space
from datetime import datetime str(datetime(2026, 9, 29, 14, 30))
Returns
'2026-09-29 14:30:00'
8. Digits past microseconds are dropped
from datetime import datetime datetime.fromisoformat('2026-09-29T14:30:05.1234567')
Returns
datetime.datetime(2026, 9, 29, 14, 30, 5, 123456)

Pitfalls

1. date.fromisoformat on a timestamp
date.fromisoformat accepts a date and nothing else. Parse a datetime and take .date().
date.fromisoformat
from datetime import date
date.fromisoformat('2026-09-29T14:30')
ValueError: Invalid isoformat string: '2026-09-29T14:30'
.date()
from datetime import datetime
datetime.fromisoformat('2026-09-29T14:30').date()
datetime.date(2026, 9, 29)
2. Unpadded numbers are not ISO 8601
ISO requires 2-digit months and days. For loose input use strptime, which accepts 9 for %m.
fromisoformat
from datetime import datetime
datetime.fromisoformat('2026-9-5')
ValueError: Invalid isoformat string: '2026-9-5'
strptime
from datetime import datetime
datetime.strptime('2026-9-5', '%Y-%m-%d')
datetime.datetime(2026, 9, 5, 0, 0)
3. Expecting isoformat to round
timespec truncates. 59.999999 seconds with timespec="seconds" stays :59 — round with a timedelta first if you need it.
truncated
from datetime import datetime
datetime(2026, 9, 29, 14, 30, 59, 999999).isoformat(timespec='seconds')
'2026-09-29T14:30:59'
round first
from datetime import datetime, timedelta
dt = datetime(2026, 9, 29, 14, 30, 59, 999999)
(dt + timedelta(microseconds=500000)).isoformat(timespec='seconds')
'2026-09-29T14:31:00'

When to use

Use it
  • Storing timestamps as text: JSON, CSV, logs, databases without a datetime type
  • Reading API timestamps (RFC 3339 is a profile of ISO 8601)
  • Form inputs of type date / time / datetime-local (they send ISO text)
Reach for something else
  • Human-facing text → strftime
  • Arbitrary layouts (29/09/2026) → strptime
  • ISO durations (P3DT4H) and intervals → not supported; third-party isodate

Notes

CPython impl
A hand-written C parser in Modules/_datetimemodule.c (parse_isoformat_date / parse_hh_mm_ss_ff); every syntax error is reported as ValueError: Invalid isoformat string: <repr>
Separator
datetime.fromisoformat accepts ANY single character between date and time (T, space, even a letter)
Offsets
An offset of zero (+00:00, -00:00, Z) gives timezone.utc itself; others give timezone(timedelta(...)); 24:00 or more is ValueError
Before 3.11
Only the formats that isoformat() itself writes were accepted — no Z, no basic format, no week dates

FAQ

On Python 3.11+ datetime.fromisoformat("2026-09-29T14:30:00Z") works directly and returns an aware datetime in UTC. On 3.7–3.10, replace the Z first: fromisoformat(s.replace("Z", "+00:00")).