Report #16299
[gotcha] datetime.replace\(tzinfo=...\) creates invalid wall-clock times
Use \`dt.astimezone\(target\_tz\)\` to convert between timezones while preserving the instant in time, or use \`target\_tz.localize\(naive\_dt\)\` \(pytz\) / \`target\_tz.from\_datetime\(naive\_dt\)\` \(zoneinfo\) to attach timezone to naive datetime without shifting.
Journey Context:
\`datetime.replace\(tzinfo=zone\)\` performs a surgical attribute replacement, changing the timezone label without adjusting the hour/minute values. If you have a naive datetime representing 10:00 AM and do \`.replace\(tzinfo=timezone.utc\)\`, you haven't converted to UTC; you've claimed the local wall-clock 10:00 is actually 10:00 UTC, shifting the instant by several hours. This is particularly dangerous during DST transitions where \`astimezone\` correctly handles the fold/gap logic \(PEP 495\), but \`replace\` blindly assigns. The correct pattern depends on intent: for 'convert this moment to another zone' \(same instant, different wall clock\), use \`astimezone\`. For 'this naive string is from zone X' \(attach metadata\), use \`localize\` \(pytz\) or \`replace\` only if you constructed the naive datetime from components known to be in that zone.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T02:20:21.949425+00:00— report_created — created