mrkeyoor.com_
Thu 06 Aug 00:57 UTC
PyPIUtilsupdated 05 Aug 2026

tzdata

tzdata is the IANA timezone database compiled with zic and repackaged as a pip-installable wheel. There is almost no code in it: just the binary TZif files for every zone plus two constants (tzdata.IANA_VERSION and __version__). It exists because of PEP 615: the stdlib zoneinfo module reads system timezone data first, and on platforms without /usr/share/zoneinfo (Windows, slim and distroless containers) it falls back to this package. Installing it is the standard fix for ZoneInfoNotFoundError, and it is how you pin timezone data independent of the host OS.

Verdict

A boring dependency in the best sense: one job, done under the python GitHub org, tracking IANA releases promptly. Install it whenever zoneinfo might run without system data, keep it unpinned, and skip it on well-maintained Linux hosts.

API stability5/5The public surface is two module constants and a directory of TZif files; there is nothing to break, and the layout has been unchanged since the package appeared.
Docs4/5tzdata.python.org is short but complete for the package's tiny scope, including how to read the data files directly; most real questions are zoneinfo questions answered in the CPython docs instead.
Maintenance5/5Maintained under the python GitHub org with automation that tracks IANA releases (2026.3 shipped July 2026 wrapping IANA 2026c), repo pushed August 2026, only 3 open issues.
Ecosystem4/5123.7M weekly downloads because pandas 2+ and many other packages depend on it as the zoneinfo data fallback; nothing extends it because there is nothing to extend.

Use it if

  • You use zoneinfo on Windows or in slim containers (python:slim, alpine, distroless) where system timezone data is missing and ZoneInfo raises ZoneInfoNotFoundError
  • You want reproducible timezone data across dev, CI, and production instead of whatever version each host OS happens to have
  • You publish a library that uses zoneinfo and needs to work everywhere: the conditional dependency tzdata; sys_platform == 'win32' (or unconditional) is the accepted pattern
  • You want timezone updates on pip's schedule: a pip install -U tzdata picks up new IANA releases without waiting for OS package updates
Skip it if

Setup reality

pip install tzdata is as painless as packaging gets: a universal pure-data wheel, no compilation, no platform variants, no dependencies. The subtle parts are behavioral. It only takes effect when zoneinfo finds nothing on TZPATH, so verifying a Windows fix from a Linux laptop proves nothing; set PYTHONTZPATH to empty to simulate. Versions are calendar-based (2026.3 wraps IANA release 2026c), and you should let it float rather than pin an exact version, because stale timezone data is a silent correctness bug, not a stability feature.

Patterns

Fix ZoneInfoNotFoundErrorfix-zoneinfo-not-found

# pip install tzdata
from zoneinfo import ZoneInfo

tz = ZoneInfo("America/New_York")  # works even with no system tz data

No import of tzdata is needed; zoneinfo discovers the package automatically when nothing is found on TZPATH. This is the whole fix for Windows and slim Docker images.

Create an aware datetime with zoneinfocreate-aware-datetime

from datetime import datetime
from zoneinfo import ZoneInfo

dt = datetime(2026, 8, 5, 12, 0, tzinfo=ZoneInfo("Asia/Kolkata"))
print(dt.isoformat())  # 2026-08-05T12:00:00+05:30

Unlike pytz, passing tzinfo directly to the constructor is correct with zoneinfo; there is no localize step.

Convert a datetime between zonesconvert-between-zones

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

now_utc = datetime.now(timezone.utc)
local = now_utc.astimezone(ZoneInfo("Europe/Paris"))
back = local.astimezone(timezone.utc)

Arithmetic on zoneinfo-aware datetimes re-resolves the UTC offset automatically across DST changes; no normalize call exists or is needed.

Check which IANA release you are runningcheck-data-version

import tzdata
from importlib.metadata import version

print(tzdata.IANA_VERSION)   # '2026c'
print(version("tzdata"))     # '2026.3'

IANA versions like 2026c are not valid PEP 440 versions, so the pip version is YYYY.n with n counting releases that year; IANA_VERSION gives the real upstream identifier.

List all available zone nameslist-available-zones

import zoneinfo

zones = zoneinfo.available_timezones()
print(len(zones))
print(sorted(zones)[:3])

available_timezones() returns an unsorted set that merges system data and the tzdata package, and it does filesystem walks on every call; cache the result instead of calling it per request.

Force the tzdata package instead of system dataforce-tzdata-over-system

# option 1: environment, before interpreter start
#   PYTHONTZPATH="" python app.py

# option 2: at runtime, before creating ZoneInfo objects
import zoneinfo
zoneinfo.reset_tzpath(to=[])
tz = zoneinfo.ZoneInfo("Europe/Paris")  # now read from tzdata wheel

With an empty TZPATH, zoneinfo can only use the tzdata package, which makes every environment read identical data; do this in tests when host OS data versions differ.

Declare tzdata in pyproject.tomldeclare-dependency

[project]
dependencies = [
  "tzdata; sys_platform == 'win32'",
]

# or unconditionally, which also covers slim Linux containers:
# dependencies = ["tzdata"]

The win32 marker misses slim and distroless Linux images that lack /usr/share/zoneinfo; depending on it unconditionally costs little and removes a whole class of deploy-time surprises.

Disambiguate repeated wall-clock times with foldambiguous-time-fold

from datetime import datetime
from zoneinfo import ZoneInfo

paris = ZoneInfo("Europe/Paris")
# 02:30 on 2026-10-25 occurs twice (clocks fall back)
first = datetime(2026, 10, 25, 2, 30, tzinfo=paris)          # fold=0
second = datetime(2026, 10, 25, 2, 30, fold=1, tzinfo=paris)
print(first.utcoffset(), second.utcoffset())  # 2:00:00 1:00:00

fold replaces pytz's is_dst: 0 picks the first occurrence, 1 the second. Nothing raises on ambiguous input, so user-entered local times near transitions need explicit handling.

Pick up new data in a long-running processreload-after-upgrade

from zoneinfo import ZoneInfo

# after pip install -U tzdata in-place:
fresh = ZoneInfo.no_cache("America/Santiago")

The normal constructor caches instances for the life of the process, so already-created zones keep old rules after an upgrade. no_cache reads fresh data but does not update datetimes holding the old instance; a restart is the honest fix.

Read the raw TZif files and zone listread-raw-tzif

from importlib.resources import files

zone_names = (files("tzdata") / "zones").read_text().splitlines()
raw = (files("tzdata.zoneinfo") / "Europe" / "Paris").read_bytes()
print(raw[:4])  # b'TZif'

The zones file lists every key the package ships; the binary files live under tzdata/zoneinfo/. Useful for tools that parse TZif themselves instead of going through zoneinfo.

Alternatives

PackageRegistryPick it when
pytzPyPILegacy codebases that predate zoneinfo and already depend on its localize/normalize API
backports.zoneinfoPyPIYou need the zoneinfo API itself on Python 3.6 to 3.8; pair it with tzdata for the data
python-dateutilPyPIYou also need parsing and recurrence rules; dateutil.tz reads system data and carries its own fallback