pola-rs/polars · error
first cast to integer before applying modulo on datelike dty
Error message
first cast to integer before applying modulo on datelike dtypes
What it means
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.).
Source
Thrown at py-polars/src/polars/series/series.py:1340
):
return self.to_frame().select(F.col(self.name) * other).to_series()
elif isinstance(other, pl.DataFrame):
return other * self
else:
return self._arithmetic(other, "mul", "mul_<>")
@overload
def __mod__(self, other: Expr) -> Expr: ...
@overload
def __mod__(self, other: Any) -> Series: ...
def __mod__(self, other: Any) -> Series | Expr:
if isinstance(other, pl.Expr):
return F.lit(self).__mod__(other)
if self.dtype.is_temporal():
msg = "first cast to integer before applying modulo on datelike dtypes"
raise TypeError(msg)
if self.dtype.is_decimal() and isinstance(other, (float, int)):
return self.to_frame().select(F.col(self.name) % other).to_series()
return self._arithmetic(other, "rem", "rem_<>")
def __rmod__(self, other: Any) -> Series:
if self.dtype.is_temporal():
msg = "first cast to integer before applying modulo on datelike dtypes"
raise TypeError(msg)
return self._arithmetic(other, "rem", "rem_<>_rhs")
def __radd__(self, other: Any) -> Series:
if isinstance(other, str) or (
isinstance(other, (int, float)) and self.dtype.is_decimal()
):
return self.to_frame().select(other + F.col(self.name)).to_series()
return self._arithmetic(other, "add", "add_<>_rhs")
def __rsub__(self, other: Any) -> Series:View on GitHub (pinned to df599052da)
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.
Example fix
// before dt = pl.Series([datetime(2024,1,1,13)]).cast(pl.Datetime) dt % 12 # TypeError // after dt.dt.hour() % 12 # 1
Defensive patterns
Strategy: type-guard
Validate before calling
if s.dtype.is_temporal():
raise SystemExit(f'refusing mod on {s.dtype}; extract a component first')
result = s % n Type guard
def supports_mod(s: pl.Series) -> bool:
return not s.dtype.is_temporal() Try / catch
try:
out = s % n
except TypeError as e:
if 'datelike' not in str(e):
raise
out = s.cast(pl.Int64) % n Prevention
- Cyclical time features should use dt.hour()/dt.weekday()/dt.ordinal_day() before %.
- No temporal dtype supports %, including Duration.
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- first cast to integer before dividing datelike dtypes
- first cast to integer before multiplying datelike dtypes
- cannot do arithmetic with Series of dtype: {self.dtype!r} an
- `dtype` must be of type {Date, Datetime, Time}
- cannot compare datetime.datetime to Series of type {self.dty
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/b94ac76c53c97fae.
Report an issue: GitHub.