pandas-dev/pandas · error · TypeError
Cannot compare tz-naive and tz-aware datetime-like objects.
Error message
Cannot compare tz-naive and tz-aware datetime-like objects.
What it means
Raised inside DatetimeArray._assert_tzawareness_compat when comparing a tz-naive DatetimeIndex/array (self.tz is None) against an operand that carries tzinfo (a tz-aware Timestamp, Series, or DatetimeIndex). Pandas refuses the operation because wall-time vs absolute-time comparison is ambiguous; the comparison would silently produce wrong results, so it errors hard. It is a TypeError.
Source
Thrown at pandas/core/arrays/datetimes.py:782
)
# -----------------------------------------------------------------
# Comparison Methods
def _assert_tzawareness_compat(self, other) -> None:
# adapted from _Timestamp._assert_tzawareness_compat
other_tz = getattr(other, "tzinfo", None)
other_dtype = getattr(other, "dtype", None)
if isinstance(other_dtype, DatetimeTZDtype):
# Get tzinfo from Series dtype
other_tz = other.dtype.tz
if other is NaT:
# pd.NaT quacks both aware and naive
pass
elif self.tz is None:
if other_tz is not None:
raise TypeError(
"Cannot compare tz-naive and tz-aware datetime-like objects."
)
elif other_tz is None:
raise TypeError(
"Cannot compare tz-naive and tz-aware datetime-like objects"
)
# -----------------------------------------------------------------
# Arithmetic Methods
def _add_offset(self, offset: BaseOffset) -> Self:
assert not isinstance(offset, Tick)
# For pure-timedelta DateOffset with tz-aware data, add to UTC values
# directly to avoid nonexistent/ambiguous time errors from
# re-localizing wall-time results near DST (GH#28610).
if (
self.tz is not NoneView on GitHub (pinned to 71959b8cb9)
Solutions
- Align both sides to the same awareness: localize the naive side with tz_localize('UTC') before comparing.
- If one side is truly UTC underneath, tz_localize then tz_convert it to the other side's tz.
- If you want a wall-time comparison, strip the aware side via tz_localize(None) (only if you accept losing absolute-time meaning).
- Audit df columns with df[col].dt.tz before any merge/join/comparison.
Example fix
# before
naive < pd.Timestamp('2020-01-01', tz='UTC')
# after
naive.tz_localize('UTC') < pd.Timestamp('2020-01-01', tz='UTC') Defensive patterns
Strategy: validation
Validate before calling
def assert_same_awareness(left, right):
l_tz = getattr(getattr(left, 'dtype', None), 'tz', None) or getattr(left, 'tzinfo', None)
r_tz = getattr(getattr(right, 'dtype', None), 'tz', None) or getattr(right, 'tzinfo', None)
if (l_tz is None) != (r_tz is None):
raise TypeError(f'awareness mismatch: left tz={l_tz}, right tz={r_tz}') Type guard
def is_tz_aware(x) -> bool:
dt = getattr(x, 'dtype', None)
return getattr(dt, 'tz', None) is not None or getattr(x, 'tzinfo', None) is not None Try / catch
try:
result = left < right
except TypeError as e:
if 'tz-naive and tz-aware' in str(e):
# localize the naive side to the aware side's tz, then retry
...
raise Prevention
- Standardize every datetime column to UTC at ingestion.
- Assert .dt.tz equality before merge/join on datetime keys.
- Never compare raw datetime.datetime.now() (naive) against DB timestamps.
When it happens
Trigger: Comparisons (==, <, >, isin, merge, between) where the left side is tz-naive and the right is tz-aware, e.g. naive_dti < pd.Timestamp('2020-01-01', tz='UTC'), or a DataFrame with a naive datetime column merged against an aware one. Also reached through Series.dt operations that delegate to the array's compare path.
Common situations: Loading data from CSV/SQL yields tz-naive timestamps while a second source (API, database with tz) is aware; user converts one column with tz_localize but forgets the other; mixing pd.Timestamp('now') (aware) with parsed strings (naive).
Related errors
- Cannot compare tz-naive and tz-aware datetime-like objects
- Cannot convert tz-naive timestamps, use tz_localize to local
- The nonexistent argument must be one of 'raise', 'NaT', 'shi
- Already tz-aware, use tz_convert to convert.
- DatetimeIndex has mixed timezones
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/4990abcb4084b27f.
Report an issue: GitHub.