{"record":{"id":"57fcd648505c516c","repo":"pola-rs/polars","slug":"datetime-time-zone-other-tzinfo-r-does-not-match","errorCode":null,"errorMessage":"datetime time zone {other.tzinfo!r} does not match Series timezone {time_zone!r}","messagePattern":"datetime time zone (.+?) does not match Series timezone (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/series/series.py","lineNumber":760,"sourceCode":"\n        elif isinstance(other, float) and self.dtype.is_integer():\n            # require upcast when comparing int series to float value\n            self = self.cast(Float64)\n            f = get_ffi_func(op + \"_<>\", Float64, self._s)\n            assert f is not None\n            return self._from_pyseries(f(other))\n\n        elif isinstance(other, datetime):\n            if self.dtype == Date:\n                # require upcast when comparing date series to datetime\n                self = self.cast(Datetime(\"us\"))\n                time_unit = \"us\"\n            elif self.dtype == Datetime:\n                # Use local time zone info\n                time_zone = self.dtype.time_zone  # type: ignore[attr-defined]\n                if str(other.tzinfo) != str(time_zone):\n                    msg = f\"datetime time zone {other.tzinfo!r} does not match Series timezone {time_zone!r}\"\n                    raise TypeError(msg)\n                time_unit = self.dtype.time_unit  # type: ignore[attr-defined]\n            else:\n                msg = f\"cannot compare datetime.datetime to Series of type {self.dtype}\"\n                raise ValueError(msg)\n            ts = datetime_to_int(other, time_unit)  # type: ignore[arg-type]\n            f = get_ffi_func(op + \"_<>\", Int64, self._s)\n            assert f is not None\n            return self._from_pyseries(f(ts))\n\n        elif isinstance(other, time) and self.dtype == Time:\n            d = time_to_int(other)\n            f = get_ffi_func(op + \"_<>\", Int64, self._s)\n            assert f is not None\n            return self._from_pyseries(f(d))\n\n        elif isinstance(other, timedelta) and self.dtype == Duration:\n            time_unit = self.dtype.time_unit  # type: ignore[attr-defined]\n            td = timedelta_to_int(other, time_unit)","sourceCodeStart":742,"sourceCodeEnd":778,"githubUrl":"https://github.com/pola-rs/polars/blob/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/py-polars/src/polars/series/series.py#L742-L778","documentation":"When comparing a Series of dtype Datetime against a Python datetime.datetime, _comp checks that the datetime's tzinfo matches the Series' time_zone. If they differ (or one is tz-aware and the other naive), Polars raises TypeError rather than silently applying a possibly-wrong timezone conversion. Timezone-aware values must agree exactly with the Series' declared timezone.","triggerScenarios":"Comparing a tz-aware Datetime Series with a datetime built with a different tzinfo (e.g. Series tz 'UTC' vs datetime with zoneinfo.ZoneInfo('America/New_York')), or comparing a tz-aware Series against a naive datetime.datetime (tzinfo None), via any of ==, !=, <, >, <=, >=.","commonSituations":"Constructing datetimes with datetime.now() (naive) and comparing against a UTC-series parsed from timestamps; mixing ZoneInfo regions with a Series stored in UTC after read_parquet/scan_csv; hard-coded datetimes from configs that omit tzinfo.","solutions":["Convert the Python datetime to the Series' timezone before comparing: dt.replace(tzinfo=ZoneInfo('UTC')) or dt.astimezone(ZoneInfo(series_tz)).","Use Polars' own literals so the timezone is handled for you: s == pl.lit(dt) or filter with pl.col('ts') == pl.lit(dt, time_zone='UTC').","For string timestamps, parse with the right tz: pl.lit('2024-01-01T00:00:00').str.to_datetime(time_zone='UTC').","Normalize both sides to the same timezone first, e.g. s.dt.convert_time_zone('UTC') and an aware datetime via astimezone(ZoneInfo('UTC'))."],"exampleFix":"// before\nfrom datetime import datetime\nimport polars as pl\ns = pl.Series('ts', [datetime(2024, 1, 1)]).dt.replace_time_zone('UTC')\ns > datetime(2024, 6, 1)  # TypeError: datetime time zone 'NoneType' does not match Series timezone 'UTC'\n\n// after\nfrom zoneinfo import ZoneInfo\ns > datetime(2024, 6, 1, tzinfo=ZoneInfo('UTC'))","handlingStrategy":"validation","validationCode":"from datetime import datetime\nfrom zoneinfo import ZoneInfo\nif dt.tzinfo is None:\n    raise ValueError('datetime must be timezone-aware to compare with tz-aware Series')\nif str(dt.tzinfo) != str(series_tz):\n    dt = dt.astimezone(ZoneInfo(series_tz))","typeGuard":"def tz_matches(dt: datetime, series_tz: str | None) -> bool:\n    return str(dt.tzinfo) == str(series_tz)","tryCatchPattern":"try:\n    result = s > dt\nexcept TypeError as e:\n    if 'does not match Series timezone' in str(e):\n        tz = s.dtype.time_zone\n        result = s > dt.astimezone(ZoneInfo(tz))\n    else:\n        raise","preventionTips":["Always create timezone-aware datetimes (datetime.now(timezone.utc)) when comparing against Datetime Series.","Normalize all datetimes to the Series' timezone (usually UTC) before comparisons.","Prefer pl.lit(dt) / expression-based filters so polars handles tz coercion.","Check s.dtype.time_zone before comparing; remember naive datetime has tzinfo None.","Parse timestamps with explicit time_zone instead of relying on Python datetime defaults."],"tags":["python","polars","timezone","datetime-comparison"],"backgroundTag":"dtype-mismatch","analyzedSha":"fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e","analyzedAt":"2026-09-18T22:14:11.667Z","contentChangedAt":"2026-09-18T22:14:11.667Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}