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
Mirror of [302]: DatetimeArray._assert_tzawareness_compat raises this variant (no trailing period in the message) when self is tz-aware but other is tz-naive. Same semantic rule — pandas will not silently compare across the awareness boundary. The two message variants exist for the two branches; the message inconsistency itself is a minor cosmetic bug.
Solutions
- Drop awareness from the aware side: `aware_obj.dt.tz_localize(None)` (keeps wall time) or `aware_obj.dt.tz_convert('UTC').dt.tz_localize(None)` (keeps UTC instant).
- Localize the naive side to match: `naive_obj.dt.tz_localize(aware_obj.dt.tz)`.
- Make the comparison reference tz-aware: `pd.Timestamp.now(tz=df['ts'].dt.tz)` instead of `pd.Timestamp.now()`.
Example fix
// before mask = df['aware_ts'] < pd.Timestamp.now() // after mask = df['aware_ts'] < pd.Timestamp.now(tz=df['aware_ts'].dt.tz)
Defensive patterns
Strategy: validation
Validate before calling
import pandas as pd
def align_aware_to_naive_other(aware, other):
other_tz = getattr(getattr(other, 'dtype', None), 'tz', getattr(other, 'tzinfo', None))
if other_tz is None:
if hasattr(other, 'dt'):
other = other.dt.tz_localize(aware.dt.tz)
elif hasattr(other, 'tz_localize'):
other = other.tz_localize(aware.dt.tz)
return aware, other Type guard
def comparison_safe(aware, other) -> bool:
other_tz = getattr(getattr(other, 'dtype', None), 'tz', getattr(other, 'tzinfo', None))
return other_tz is not None Try / catch
try:
result = aware == other
except TypeError as e:
if 'Cannot compare tz-naive and tz-aware' in str(e):
other = pd.Timestamp(other).tz_localize(aware.dt.tz)
result = aware == other
else:
raise Prevention
- Use `pd.Timestamp.now(tz=col.dt.tz)` instead of `pd.Timestamp.now()` for comparisons.
- Localize naive reference values at the point of construction.
When it happens
Trigger: Comparison or alignment where the left/own side is tz-aware and the right/other side is tz-naive. Concretely: `aware_dti == naive_ts`, `aware_series < naive_dti`, set ops between an aware index and a naive index.
Common situations: Default Timestamps (`pd.Timestamp.now()` is naive) compared against tz-aware columns loaded from a database with UTC offsets. Intersecting a tz-aware DatetimeIndex built via tz_localize with one constructed from naive strings.
Related errors
- Cannot compare tz-naive and tz-aware datetime-like objects.
- Already tz-aware, use tz_convert to convert.
- Cannot convert tz-naive timestamps, use tz_localize to…
- Cannot pass both a timezone-aware dtype and tz=None
- cannot supply both a tz and a dtype with a tz
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/6e3805f65b7e107c.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/datetimes.py:786
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 None
and isinstance(offset, RelativeDeltaOffset)
and not offset._use_relativedelta
):
# GH#64806 _add_timedeltalike_scalar casts to the finer of the twoView on GitHub (pinned to 3b7651241d)