{"record":{"id":"6e3805f65b7e107c","repo":"pandas-dev/pandas","slug":"cannot-compare-tz-naive-and-tz-aware-datetime-like-6e3805","errorCode":null,"errorMessage":"Cannot compare tz-naive and tz-aware datetime-like objects","messagePattern":"Cannot compare tz-naive and tz-aware datetime-like objects","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/datetimes.py","lineNumber":786,"sourceCode":"\n    def _assert_tzawareness_compat(self, other) -> None:\n        # adapted from _Timestamp._assert_tzawareness_compat\n        other_tz = getattr(other, \"tzinfo\", None)\n        other_dtype = getattr(other, \"dtype\", None)\n\n        if isinstance(other_dtype, DatetimeTZDtype):\n            # Get tzinfo from Series dtype\n            other_tz = other.dtype.tz\n        if other is NaT:\n            # pd.NaT quacks both aware and naive\n            pass\n        elif self.tz is None:\n            if other_tz is not None:\n                raise TypeError(\n                    \"Cannot compare tz-naive and tz-aware datetime-like objects.\"\n                )\n        elif other_tz is None:\n            raise TypeError(\n                \"Cannot compare tz-naive and tz-aware datetime-like objects\"\n            )\n\n    # -----------------------------------------------------------------\n    # Arithmetic Methods\n\n    def _add_offset(self, offset: BaseOffset) -> Self:\n        assert not isinstance(offset, Tick)\n\n        # For pure-timedelta DateOffset with tz-aware data, add to UTC values\n        # directly to avoid nonexistent/ambiguous time errors from\n        # re-localizing wall-time results near DST (GH#28610).\n        if (\n            self.tz is not None\n            and isinstance(offset, RelativeDeltaOffset)\n            and not offset._use_relativedelta\n        ):\n            # GH#64806 _add_timedeltalike_scalar casts to the finer of the two","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/datetimes.py#L768-L804","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()`."],"exampleFix":"// before\nmask = df['aware_ts'] < pd.Timestamp.now()\n\n// after\nmask = df['aware_ts'] < pd.Timestamp.now(tz=df['aware_ts'].dt.tz)","handlingStrategy":"validation","validationCode":"import pandas as pd\n\ndef align_aware_to_naive_other(aware, other):\n    other_tz = getattr(getattr(other, 'dtype', None), 'tz', getattr(other, 'tzinfo', None))\n    if other_tz is None:\n        if hasattr(other, 'dt'):\n            other = other.dt.tz_localize(aware.dt.tz)\n        elif hasattr(other, 'tz_localize'):\n            other = other.tz_localize(aware.dt.tz)\n    return aware, other","typeGuard":"def comparison_safe(aware, other) -> bool:\n    other_tz = getattr(getattr(other, 'dtype', None), 'tz', getattr(other, 'tzinfo', None))\n    return other_tz is not None","tryCatchPattern":"try:\n    result = aware == other\nexcept TypeError as e:\n    if 'Cannot compare tz-naive and tz-aware' in str(e):\n        other = pd.Timestamp(other).tz_localize(aware.dt.tz)\n        result = aware == other\n    else:\n        raise","preventionTips":["Use `pd.Timestamp.now(tz=col.dt.tz)` instead of `pd.Timestamp.now()` for comparisons.","Localize naive reference values at the point of construction."],"tags":["datetime","timezone","comparison","tz-aware"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}