pola-rs/polars · error · TypeError
datetime time zone does not match Series timezone
Error message
datetime time zone {other.tzinfo!r} does not match Series timezone {time_zone!r} What it means
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.
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')).
Example fix
// before
from datetime import datetime
import polars as pl
s = pl.Series('ts', [datetime(2024, 1, 1)]).dt.replace_time_zone('UTC')
s > datetime(2024, 6, 1) # TypeError: datetime time zone 'NoneType' does not match Series timezone 'UTC'
// after
from zoneinfo import ZoneInfo
s > datetime(2024, 6, 1, tzinfo=ZoneInfo('UTC')) Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime
from zoneinfo import ZoneInfo
if dt.tzinfo is None:
raise ValueError('datetime must be timezone-aware to compare with tz-aware Series')
if str(dt.tzinfo) != str(series_tz):
dt = dt.astimezone(ZoneInfo(series_tz)) Type guard
def tz_matches(dt: datetime, series_tz: str | None) -> bool:
return str(dt.tzinfo) == str(series_tz) Try / catch
try:
result = s > dt
except TypeError as e:
if 'does not match Series timezone' in str(e):
tz = s.dtype.time_zone
result = s > dt.astimezone(ZoneInfo(tz))
else:
raise Prevention
- 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.
When it happens
Trigger: 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 ==, !=, <, >, <=, >=.
Common situations: 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.
Related errors
- cannot compare datetime.datetime to Series of type
- time zone of dtype ( ) differs from time zone of value ( )
- accessing ` ` from the top-level `polars` module was…
- altair>=5.4.0 is required for `.plot`
- `arctan2` expected a `str` or `Expr` got a
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/57fcd648505c516c.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/series/series.py:760
elif isinstance(other, float) and self.dtype.is_integer():
# require upcast when comparing int series to float value
self = self.cast(Float64)
f = get_ffi_func(op + "_<>", Float64, self._s)
assert f is not None
return self._from_pyseries(f(other))
elif isinstance(other, datetime):
if self.dtype == Date:
# require upcast when comparing date series to datetime
self = self.cast(Datetime("us"))
time_unit = "us"
elif self.dtype == Datetime:
# Use local time zone info
time_zone = self.dtype.time_zone # type: ignore[attr-defined]
if str(other.tzinfo) != str(time_zone):
msg = f"datetime time zone {other.tzinfo!r} does not match Series timezone {time_zone!r}"
raise TypeError(msg)
time_unit = self.dtype.time_unit # type: ignore[attr-defined]
else:
msg = f"cannot compare datetime.datetime to Series of type {self.dtype}"
raise ValueError(msg)
ts = datetime_to_int(other, time_unit) # type: ignore[arg-type]
f = get_ffi_func(op + "_<>", Int64, self._s)
assert f is not None
return self._from_pyseries(f(ts))
elif isinstance(other, time) and self.dtype == Time:
d = time_to_int(other)
f = get_ffi_func(op + "_<>", Int64, self._s)
assert f is not None
return self._from_pyseries(f(d))
elif isinstance(other, timedelta) and self.dtype == Duration:
time_unit = self.dtype.time_unit # type: ignore[attr-defined]
td = timedelta_to_int(other, time_unit)View on GitHub (pinned to fe841f959e)