Report #16169
[gotcha] datetime.replace\(tzinfo=...\) changes wall clock instead of converting timezone
Use datetime.astimezone\(target\_tz\) to convert an aware datetime to another timezone while preserving the absolute moment in time. Only use datetime.replace\(tzinfo=tz\) when the datetime is naive and you are asserting its existing wall clock value corresponds to that specific timezone offset without shifting the time.
Journey Context:
Developers migrating from naive datetimes often assume replace\(\) works like astimezone\(\), expecting it to convert 3pm NYC to 8pm UTC. However, replace\(\) performs surgery on the tzinfo attribute only, changing 3pm NYC to 3pm UTC—a completely different moment in time \(off by 5 hours\). This causes silent data corruption when storing to UTC-normalized databases or APIs. The distinction is between 'wall time' \(what a clock on the wall shows\) and 'absolute time' \(the specific instant in history\). astimezone\(\) preserves absolute time by adjusting the wall clock; replace\(\) preserves wall time by changing the absolute time. This is particularly dangerous when parsing RFC 3339 strings with offsets and then calling replace\(\) to 'convert' to UTC.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T01:56:30.613576+00:00— report_created — created