Fix "can't compare offset-naive and offset-aware datetimes"
TypeError: can't compare offset-naive and offset-aware datetimes means you mixed timezone-aware and naive datetimes. Learn the aware-vs-naive model, zoneinfo, and astimezone conversions.
You've hit one of Python's most infamous tracebacks: TypeError: can't compare offset-naive and offset-aware datetimes It shows up when you subtract two datetimes, sort a list of them, or filter "everything after X" — and one side knows its timezone while the other doesn't. Python refuses to guess, because guessing wrong means silently comparing 3 PM in Karachi with 3 PM in UTC as if they were the same moment. They're five hours apart. This tutorial gives you the mental model that makes the error disappear permanently: naive vs aware, zoneinfo , and astimezone . What you'll learn The naive-vs-aware mental model behind the error How to reproduce the TypeError and fix it correctly How to make naive datetimes aware (and when that's the wrong fix) zoneinfo in Python 3.9+: timezones without third-party packages Converting between timezones with astimezone Why datetime.utcnow() is deprecated and what replaces it Step 1 — Reproduce the error Let's trigger it on purpose so the fix lands: from datetime import datetime, timezone naive = datetime(2026, 10, 1, 12, 0) # no timezone info aware = datetime(2026, 10, 1, 12, 0, tzinfo=timezone.utc) # knows it's UTC try: print(naive < aware) except TypeError as e: print(f"TypeError: {e}") # TypeError: can't compare offset-naive and offset-aware datetimes Both print as 2026-10-01 12:00:00 (the aware one adds +00:00 ), but they're different kinds of object. The naive one is a wall-clock reading with no location — "noon, somewhere." The aware one is a precise instant. Comparing them is meaningless, so Python raises TypeError instead of returning a wrong boolean. The same error comes from - (subtraction), sorted() , min / max , and > / < / == ... well, == between naive and aware actually…