{"record":{"id":"9fb10f4194706d30","repo":"pola-rs/polars","slug":"cannot-compare-datetime-datetime-to-series-of-type","errorCode":null,"errorMessage":"cannot compare datetime.datetime to Series of type {self.dtype}","messagePattern":"cannot compare datetime\\.datetime to Series of type (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/series/series.py","lineNumber":878,"sourceCode":"            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)\n            f = get_ffi_func(op + \"_<>\", Int64, self._s)\n            assert f is not None\n            return self._from_pyseries(f(td))\n","sourceCodeStart":860,"sourceCodeEnd":896,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/series/series.py#L860-L896","documentation":"Raised in Series._comp (py-polars/src/polars/series/series.py:878) when comparing against a datetime.datetime scalar but the Series dtype is neither Date nor Datetime. Polars has special-cased comparison paths for date/datetime/time/timedelta scalars; a datetime falls into that dispatcher, and if the Series holds e.g. Int64, String, or Duration, the combination is meaningless and rejected with ValueError naming the actual dtype.","triggerScenarios":"pl.Series([1, 2, 3]) < datetime(2024, 1, 1); pl.Series([\"a\"]).eq(datetime.now()); comparing a Duration or Time Series to a datetime instance.","commonSituations":"Type drift: a column expected to be Datetime was parsed as String/Int (e.g. CSV ingestion without schema hints, or epoch integers not converted); unit tests comparing the wrong series; mixing up time and datetime objects.","solutions":["Convert the Series to Datetime first: s.cast(pl.Datetime) or s.str.to_datetime() for strings, or pl.from_epoch(s, time_unit=\"ms\") for integers","If the scalar side is wrong (you meant a date/time/duration), use the matching Python type so the correct branch is taken","Add schema validation after ingestion so dtype surprises surface before comparison logic"],"exampleFix":"# before\ns = pl.Series([\"2024-01-01\", \"2024-06-01\"])  # strings\ns > datetime(2024, 3, 1)  # ValueError\n\n# after\ns = s.str.to_datetime()\ns > datetime(2024, 3, 1)\n# for epoch ints: s = pl.from_epoch(s, time_unit=\"s\").cast(pl.Datetime(\"us\"))","handlingStrategy":"validation","validationCode":"import polars as pl\nfrom datetime import datetime\n\ndef comparable_to_datetime(s: pl.Series) -> bool:\n    return s.dtype in (pl.Date, pl.Datetime) or (isinstance(s.dtype, pl.Datetime))\n\nif not comparable_to_datetime(s):\n    raise TypeError(f\"{s.dtype} Series cannot be compared to datetime; cast first\")","typeGuard":"def is_temporal_series(s: pl.Series) -> bool:\n    return s.dtype.base_type() in (pl.Date, pl.Datetime)","tryCatchPattern":"try:\n    mask = s > cutoff\nexcept ValueError as e:\n    if \"cannot compare datetime.datetime\" in str(e):\n        s = s.str.to_datetime() if s.dtype == pl.String else s.cast(pl.Datetime)\n        mask = s > cutoff\n    else:\n        raise","preventionTips":["Validate dtypes right after ingestion: assert df.schema[\"ts\"] == pl.Datetime(\"us\", \"UTC\")","Convert epoch integers with pl.from_epoch and strings with str.to_datetime before comparisons"],"tags":["polars","series","datetime","dtype","valueerror","comparison"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}