{"record":{"id":"b94ac76c53c97fae","repo":"pola-rs/polars","slug":"first-cast-to-integer-before-applying-modulo-on-da","errorCode":null,"errorMessage":"first cast to integer before applying modulo on datelike dtypes","messagePattern":"first cast to integer before applying modulo on datelike dtypes","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/series/series.py","lineNumber":1340,"sourceCode":"        ):\n            return self.to_frame().select(F.col(self.name) * other).to_series()\n        elif isinstance(other, pl.DataFrame):\n            return other * self\n        else:\n            return self._arithmetic(other, \"mul\", \"mul_<>\")\n\n    @overload\n    def __mod__(self, other: Expr) -> Expr: ...\n\n    @overload\n    def __mod__(self, other: Any) -> Series: ...\n\n    def __mod__(self, other: Any) -> Series | Expr:\n        if isinstance(other, pl.Expr):\n            return F.lit(self).__mod__(other)\n        if self.dtype.is_temporal():\n            msg = \"first cast to integer before applying modulo on datelike dtypes\"\n            raise TypeError(msg)\n        if self.dtype.is_decimal() and isinstance(other, (float, int)):\n            return self.to_frame().select(F.col(self.name) % other).to_series()\n        return self._arithmetic(other, \"rem\", \"rem_<>\")\n\n    def __rmod__(self, other: Any) -> Series:\n        if self.dtype.is_temporal():\n            msg = \"first cast to integer before applying modulo on datelike dtypes\"\n            raise TypeError(msg)\n        return self._arithmetic(other, \"rem\", \"rem_<>_rhs\")\n\n    def __radd__(self, other: Any) -> Series:\n        if isinstance(other, str) or (\n            isinstance(other, (int, float)) and self.dtype.is_decimal()\n        ):\n            return self.to_frame().select(other + F.col(self.name)).to_series()\n        return self._arithmetic(other, \"add\", \"add_<>_rhs\")\n\n    def __rsub__(self, other: Any) -> Series:","sourceCodeStart":1322,"sourceCodeEnd":1358,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/series/series.py#L1322-L1358","documentation":"Raised by Series.__mod__ when applying `%` to any temporal Series, including Duration (there is no Duration exemption here). Modulo on a datelike value is ambiguous - there is no defined unit - so Polars asks you to cast to an integer or extract the component you actually want the remainder of (hour, weekday, etc.).","triggerScenarios":"Calling `%` on a Series with self.dtype.is_temporal() and a non-Expr right operand: `datetime_series % 2`, `duration_series % 7`, `date_series % s_int`.","commonSituations":"Cyclical-time features in ML pipelines ('hour % 12', 'day_of_year % 7'); porting pandas/numpy code that applied modulo directly to datetime64 columns; wrap-around bucketing of durations.","solutions":["Extract the component first, then mod: `s.dt.hour() % 12`, `s.dt.weekday() % 7`, `s.dt.ordinal_day() % 7`.","Cast to integer if you truly want the raw epoch remainder: `s.cast(pl.Int64) % n`.","For durations, use totals: `s.dt.total_hours() % 24`.","In expressions/DataFrames the same rule applies - keep the mod on the extracted numeric column."],"exampleFix":"// before\ndt = pl.Series([datetime(2024,1,1,13)]).cast(pl.Datetime)\ndt % 12  # TypeError\n\n// after\ndt.dt.hour() % 12  # 1","handlingStrategy":"type-guard","validationCode":"if s.dtype.is_temporal():\n    raise SystemExit(f'refusing mod on {s.dtype}; extract a component first')\nresult = s % n","typeGuard":"def supports_mod(s: pl.Series) -> bool:\n    return not s.dtype.is_temporal()","tryCatchPattern":"try:\n    out = s % n\nexcept TypeError as e:\n    if 'datelike' not in str(e):\n        raise\n    out = s.cast(pl.Int64) % n","preventionTips":["Cyclical time features should use dt.hour()/dt.weekday()/dt.ordinal_day() before %.","No temporal dtype supports %, including Duration."],"tags":["polars","series","arithmetic","temporal","dtype","mod"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}