How it works
zoneinfo, available from Python 3.9, reads IANA time-zone rules. A named zone can use different UTC offsets on different dates; a fixed offset is not equivalent to a regional zone.
These examples require available IANA data. Python uses system data or the separately installed tzdata package; some Windows installations need python -m pip install tzdata. Missing data raises ZoneInfoNotFoundError. Run these examples in a local Python environment if the browser runtime lacks zoneinfo or its data.
Limitations and practical choices
Use aware datetimes and UTC when identifying an instant. replace(tzinfo=...) attaches an interpretation; it does not convert an existing instant.
Local clock times can repeat or be skipped around daylight-saving transitions. fold distinguishes the two occurrences of a repeated time; applications still need a policy for ambiguous or nonexistent user-entered times.
Try it yourself
Convert the same UTC hour in January and July to London time. Then explain why storing only a local hour without date and zone is insufficient.
Syntax
from zoneinfo import ZoneInfo
local = instant.astimezone(ZoneInfo("Europe/London"))Examples
Convert a winter instant
Translate a known UTC instant into regional time.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
instant = datetime(2024, 1, 15, 12, tzinfo=timezone.utc)
local = instant.astimezone(ZoneInfo("Europe/London"))
print(local.isoformat())- The source datetime explicitly identifies noon UTC. astimezone preserves that instant while expressing it under London’s rules.
- The January date has a zero UTC offset, so the displayed hour remains twelve. isoformat includes the offset rather than hiding it.
- Use this when presenting stored UTC timestamps to a regional audience. IANA data must be installed.
- Expected output: 2024-01-15T12:00:00+00:00
Account for summer time
Use the rules for a different date rather than a constant offset.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
instant = datetime(2024, 7, 15, 12, tzinfo=timezone.utc)
print(instant.astimezone(ZoneInfo("Europe/London")).isoformat())- The UTC hour is again twelve, but London’s July offset is one hour ahead for this historical date.
- The conversion produces thirteen with +01:00. Adding a permanent one-hour offset would have been wrong for the winter example.
- Use named zones for regional schedules, and remember that governments can change future rules and time-zone data needs maintenance.
- Expected output: 2024-07-15T13:00:00+01:00
Distinguish a repeated hour
Identify both occurrences of a local time during a clock change.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
zone = ZoneInfo("Europe/London")
first = datetime(2024, 10, 27, 1, 30, tzinfo=zone, fold=0)
second = first.replace(fold=1)
print(first.astimezone(timezone.utc).isoformat())
print(second.astimezone(timezone.utc).isoformat())- The local 01:30 occurs twice on this transition date. fold=0 chooses the earlier occurrence and fold=1 the later one.
- Converting both to UTC exposes the one-hour difference even though their local clock fields look identical.
- Ask for or define an ambiguity policy when accepting local booking times; a timezone name alone does not choose between repeated occurrences.
- Expected output: 2024-10-27T00:30:00+00:00 2024-10-27T01:30:00+00:00
Best practices
- Use aware datetimes and UTC when identifying an instant. replace(tzinfo=...) attaches an interpretation; it does not convert an existing instant.
- Local clock times can repeat or be skipped around daylight-saving transitions. fold distinguishes the two occurrences of a repeated time; applications still need a policy for ambiguous or nonexistent user-entered times.
Runtime & versions
Python interpreter. Feature availability depends on the language and runtime version used by your project; consult the official reference below.
Python language reference