Last updated: Apr 11, 2024
Reading time·5 min

The Python "TypeError: can't compare offset-naive and offset-aware datetimes"
occurs when you try to compare a datetime that is unaware of the timezone with
one that is aware of the timezone.
To solve the error, either make both datetime objects aware of the timezone
or make them naive.
Here is an example of how the error occurs.
from datetime import datetime import pytz tz = pytz.timezone('America/New_York') dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=tz) dt_naive = datetime(2024, 9, 30, 9, 30, 0) # ⛔️ TypeError: can't compare offset-naive and offset-aware datetimes if dt_aware > dt_naive: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')

Make sure you have the pytz module installed to be able to use it.
pip install pytz # or with pip3 pip3 install pytz
Notice that the first datetime is offset-aware and the second datetime is
offset-naive.
The timezone of the first datetime is set to America/New_York.
Python is telling us that we cannot compare a datetime that has its timezone
set with one that doesn't.
tzinfo of both datetimes to utc before the comparisonOne way to solve the error is to set the timezone info of both datetimes to
utc.
from datetime import datetime import pytz tz = pytz.timezone('America/New_York') utc = pytz.UTC dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=tz).replace(tzinfo=utc) dt_naive = datetime(2024, 9, 30, 9, 30, 0).replace(tzinfo=utc) if dt_aware > dt_naive: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')

Initially, the first datetime has its timezone set to America/New_York and
the timezone wasn't set on the second datetime.
We used the datetime.replace method to set the timezone of both datetimes to UTC.
Now that the datetimes have the same offset, the comparison is allowed.
The
datetime.replace
method returns a datetime with the same attributes, except for those
attributes that were passed as keyword arguments to the method.
You can set the tzinfo keyword argument to None to create a naive datetime
from an aware datetime without converting the date and time data.
from datetime import datetime import pytz tz = pytz.timezone('America/New_York') dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=tz).replace(tzinfo=None) dt_naive = datetime(2024, 9, 30, 9, 30, 0).replace(tzinfo=None) if dt_aware > dt_naive: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')

The replace() method makes both datetime objects offset-naive before the
comparison, so everything works as expected.
localize() method to make both datetime objects offset-awareYou can also use the localize() method from the pytz module to make both
datetime objects offset-aware.
from datetime import datetime import pytz utc = pytz.UTC dt_aware = utc.localize(datetime(2024, 9, 20, 12, 0, 0)) dt_naive = utc.localize(datetime(2024, 9, 30, 9, 30, 0)) if dt_aware > dt_naive: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')
Both datetime objects are now offset-aware, so the comparison is allowed.
However, this approach cannot be used when the tzinfo of the datetime object
is already set.
from datetime import datetime import pytz tz = pytz.timezone('America/New_York') utc = pytz.UTC # ⛔️ ValueError: Not naive datetime (tzinfo is already set) dt_aware = utc.localize(datetime(2024, 9, 20, 12, 0, 0, tzinfo=tz))
Trying to call the localize() method with a datetime object that has its
timezone already set raises a ValueError.
In this case, you have the use the datetime.replace() method as shown in the
previous subheading.
You might also get the error when working with a timestamp.
from datetime import datetime import pytz dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=pytz.UTC) dt_naive = datetime.now() # ⛔️ TypeError: can't compare offset-naive and offset-aware datetimes if dt_aware > dt_naive: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')
The datetime.datetime.now() method is not timezone-aware, so trying to compare
its output with a timezone-aware datetime object is not allowed.
One way to solve the error is to use the datetime() class to convert the
timestamp to a timezone-aware datetime object.
from datetime import datetime import pytz dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=pytz.UTC) dt_naive = datetime.now() dt_aware_now = datetime( year=dt_naive.year, month=dt_naive.month, day=dt_naive.day, hour=dt_naive.hour, minute=dt_naive.minute, second=dt_naive.second, tzinfo=pytz.UTC ) if dt_aware > dt_aware_now: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')

We used the datetime() class to construct a datetime aware object from the
timestamp.
Notice that we set the tzinfo parameter to keyword argument to pytz.UTC.
Now both datetime objects are offset-aware, so the comparison is allowed.
You can also:
tzinfo attribute on the timezone-aware datetime object.tzinfo value as an argument to the datetime.datetime.now()
method.from datetime import datetime import pytz dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=pytz.UTC) timezone = dt_aware.tzinfo dt_aware_now = datetime.now(timezone) if dt_aware > dt_aware_now: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')

The tzinfo attribute returns the timezone info object of the datetime.
We passed the same timezone info object to the datetime.datetime.now() method,
so both datetime objects are offset-aware.
As shown in the previous subheading, the datetime.datetime.now() method is not
timezone-aware.
However, if you use Django, you can call the timezone.now() method instead.
from datetime import datetime import pytz from django.utils import timezone dt_aware = datetime(2024, 9, 20, 12, 0, 0, tzinfo=pytz.UTC) now = timezone.now() if dt_aware > now: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_naive')
The timezone.now() method is offset-aware.
Note that this approach can only be used in a Django application.
If the USE_TZ setting is set to True, then timezone.now() returns a
timezone-aware datetime object even if the pytz module is not installed.
If you'd rather not install third-party libraries to solve the error, import and
use the timezone and timedelta classes.
from datetime import datetime, timezone, timedelta dt_aware = datetime.strptime( '2024-09-30T09:30:05+0000', '%Y-%m-%dT%H:%M:%S%z' ) print(dt_aware) # 👉️ 2024-09-30 09:30:05+00:00 dt_aware_2 = datetime( 2025, 9, 24, tzinfo=timezone(offset=timedelta()) ) print(dt_aware_2) # 👉️ 2025-09-24 00:00:00+00:00 if dt_aware > dt_aware_2: print('dt_aware is greater than dt_naive') else: print('dt_aware is not greater than dt_aware_2')
The timedelta class represents the difference between two datetime objects.
We set the tzinfo keyword argument when instantiating the second datetime
object, so both objects are offset-aware.
You can learn more about the related topics by checking out the following tutorials: