Hands-on zoneinfo.ZoneInfo vs fixed UTC offset conversions: real conv/s on many datetimes, measured on Linux localhost today in this hands-on lab for SREs.
4 min read
Convert many datetimes with zoneinfo.ZoneInfo vs fixed datetime.timezone offsets vs naive timedelta math (stdlib only — no pytz). This lab reports conversions/s on Linux localhost.
Frame: prefer zoneinfo for real TZ rules; fixed offsets only when rules are truly fixed (e.g. always UTC+05:30). Affiliates: 0.
Related links:
Lab honesty (1 Oct 2026 IST): Python 3.13.5. 20000 hourly stamps. Zones: UTC, Asia/Kolkata, America/New_York.
Verdict up front: astimezone(fixed IST) ~3937539 conv/s; astimezone(ZoneInfo Kolkata) ~3718035; astimezone(New_York) ~3627156; naive +05:30 ~25248859 (not a TZ conversion). DST check NY winter offset -18000.0 s vs summer -14400.0 s.
| Arm | Meaning |
|---|---|
attach timezone.utc / ZoneInfo UTC | stamp tzinfo |
| attach fixed IST / ZoneInfo Kolkata | stamp tzinfo |
astimezone fixed vs ZoneInfo | real convert |
astimezone New_York | DST rules |
naive + timedelta(5:30) | offset math only |
| isoformat after convert | string path |
Script: lab-evidence/111-zoneinfo-vs-utc-offset/results/run_lab.py.
| Arm | conv/s |
|---|---|
| naive +05:30 | 25248859 |
| astimezone timezone.utc | 24853396 |
| attach ZoneInfo Kolkata | 14399906 |
| attach fixed IST | 8072214 |
| astimezone fixed IST | 3937539 |
| astimezone ZoneInfo Kolkata | 3718035 |
| astimezone ZoneInfo NY | 3627156 |
Fixed IST vs ZoneInfo Kolkata astimezone sit in the same band here — Kolkata has no DST, so rules collapse to a constant offset. New_York still needs zoneinfo (winter/summer offsets differ).
| Arm | conv/s |
|---|---|
| attach timezone.utc | 15169247 |
| attach ZoneInfo UTC | 14411963 |
| isoformat ZoneInfo Kolkata | 943588 |
| isoformat fixed IST | 984936 |
String formatting dominates once you leave pure conversion.
Store UTC aware (timezone.utc or ZoneInfo UTC), convert to ZoneInfo only at the edges (API, UI, reports). That keeps math simple and still pays zoneinfo only where humans read clocks.
ZoneInfo("Area/City").timezone.utc / fixed timezone(timedelta(...)).datetime + timedelta as a substitute for TZ rules across DST.Asia/Kolkata is a popular fixed-offset example (+05:30, no DST). Matching ZoneInfo against timezone(timedelta(hours=5, minutes=30)) is expected to be close — and it was here. That agreement must not be generalized to America/New_York or Europe/London. The NY winter/summer offset split in this lab exists specifically to catch that mistake.
Classic pytz patterns (localize / normalize) are unnecessary for new code on Python 3.9+. Stick to aware datetimes + ZoneInfo + astimezone. If you still maintain pytz call sites, migrate at the boundary rather than mixing both in one hot path.
astimezone.Evidence: summary.json, summary.txt.
One Linux box. System tzdata required for ZoneInfo. Not database TIMESTAMP WITH TIME ZONE round-trips.
For Kolkata, ZoneInfo ~3718035 conv/s ≈ fixed offset ~3937539. Still prefer zoneinfo so DST zones (NY winter -18000 s / summer -14400 s) stay correct — fixed offsets only when the contract is truly fixed.
Lab evidence
Lab 1 Oct 2026 IST. Python 3.13.5. n=20000: astimezone fixed IST 3937539 conv/s; ZoneInfo Kolkata 3718035; ZoneInfo NY 3627156. stdlib only. Affiliates: 0. Evidence: lab-evidence/111-zoneinfo-vs-utc-offset/.
Hands-on platform.platform vs os.uname host inventory lab: real ops/s plus cache notes, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20264 min read
Hands-on uuid.uuid4 vs uuid.uuid1 ID generation lab: real ops/s plus version/node checks, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20263 min read
Hands-on signal SIGUSR1 vs threading.Event wakeup lab: real p50 latency in microseconds, measured on Linux localhost today in this hands-on lab for SREs.
Summary1 Oct 20264 min read