pola-rs/polars · error

comparing datetimes with different units or timezones is not

Error message

comparing datetimes with different units or timezones is not supported

What it means

AnyValue::partial_cmp panics when ordering two Datetime scalars whose time units (us/ms/ns) or time zones differ. The raw i64 counts are only comparable after unit/timezone alignment, which the scalar comparison deliberately does not perform.

Source

Thrown at crates/polars-core/src/datatypes/any_value.rs:1410

            (UInt32(l), UInt32(r)) => l.partial_cmp(r),
            (UInt64(l), UInt64(r)) => l.partial_cmp(r),
            (UInt128(l), UInt128(r)) => l.partial_cmp(r),
            (Int8(l), Int8(r)) => l.partial_cmp(r),
            (Int16(l), Int16(r)) => l.partial_cmp(r),
            (Int32(l), Int32(r)) => l.partial_cmp(r),
            (Int64(l), Int64(r)) => l.partial_cmp(r),
            (Int128(l), Int128(r)) => l.partial_cmp(r),
            (Float16(l), Float16(r)) => Some(l.tot_cmp(r)),
            (Float32(l), Float32(r)) => Some(l.tot_cmp(r)),
            (Float64(l), Float64(r)) => Some(l.tot_cmp(r)),
            (String(l), String(r)) => l.partial_cmp(r),
            (Binary(l), Binary(r)) => l.partial_cmp(r),
            #[cfg(feature = "dtype-date")]
            (Date(l), Date(r)) => l.partial_cmp(r),
            #[cfg(feature = "dtype-datetime")]
            (Datetime(lt, lu, lz), Datetime(rt, ru, rz)) => {
                if lu != ru || lz != rz {
                    unimplemented!(
                        "comparing datetimes with different units or timezones is not supported"
                    );
                }

                lt.partial_cmp(rt)
            },
            #[cfg(feature = "dtype-duration")]
            (Duration(lt, lu), Duration(rt, ru)) => {
                if lu != ru {
                    unimplemented!("comparing durations with different units is not supported");
                }

                lt.partial_cmp(rt)
            },
            #[cfg(feature = "dtype-time")]
            (Time(l), Time(r)) => l.partial_cmp(r),
            #[cfg(feature = "dtype-categorical")]
            (Categorical(l_cat, l_map), Categorical(r_cat, r_map)) => unsafe {

View on GitHub (pinned to df599052da)

Solutions

  1. Align time units before comparing: col.dt.cast_time_unit('us') (or convert_time_unit in expressions)
  2. Align time zones: use dt.convert_time_zone(...) / dt.replace_time_zone(...) so both sides have the same tz (including both naive)
  3. Cast both columns to a single canonical Datetime dtype (e.g. .cast(pl.Datetime('us', 'UTC'))) before extracting scalars

Example fix

# before
av_cmp = df1["ts"].get(0) < df2["ts"].get(0)  # ms vs us -> panic

# after
ts1 = df1["ts"].dt.cast_time_unit("us").get(0)
ts2 = df2["ts"].dt.cast_time_unit("us").get(0)
av_cmp = ts1 < ts2
Defensive patterns

Strategy: validation

Validate before calling

def datetimes_comparable(a: pl.Series, b: pl.Series) -> bool:
    da, db = a.dtype, b.dtype
    return (
        isinstance(da, pl.Datetime) and isinstance(db, pl.Datetime)
        and da.time_unit == db.time_unit
        and da.time_zone == db.time_zone
    )

Type guard

def aligned_datetime(s: pl.Series, unit: str = "us", tz=None) -> pl.Series:
    s = s.dt.cast_time_unit(unit)
    if tz is not None:
        s = s.dt.convert_time_zone(tz)
    elif s.dtype.time_zone is not None:
        s = s.dt.replace_time_zone(None)
    return s

Prevention

When it happens

Trigger: Ordering comparisons (<, >, min/max, sort keys) between datetime AnyValues from columns with different dtypes, e.g. Datetime('ms') vs Datetime('us'), or a tz-aware Datetime('us', 'UTC') against a naive Datetime('us').

Common situations: Merging frames where one writer produced millisecond and another microsecond timestamps, comparing tz-aware against naive datetimes, or generic scalar-min/max utilities over mixed datetime columns.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/7ce0f7ffa9d86295. Report an issue: GitHub.