pola-rs/polars · error

comparing durations with different units is not supported

Error message

comparing durations with different units is not supported

What it means

AnyValue::partial_cmp panics when ordering two Duration scalars with different time units (us/ms/ns). Durations are raw i64 counts in a unit; cross-unit ordering would be wrong without conversion, which this scalar path does not do.

Source

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

            (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 {
                let l_str = l_map.cat_to_str_unchecked(*l_cat);
                let r_str = r_map.cat_to_str_unchecked(*r_cat);
                l_str.partial_cmp(r_str)
            },
            #[cfg(feature = "dtype-categorical")]
            (Enum(l_cat, l_map), Enum(r_cat, r_map)) => {
                if !Arc::ptr_eq(l_map, r_map) {
                    unimplemented!("can't order enums from different FrozenCategories")
                }
                l_cat.partial_cmp(r_cat)

View on GitHub (pinned to df599052da)

Solutions

  1. Cast duration columns to one unit before comparing: col.dt.cast_time_unit('us') works for durations too, or .cast(pl.Duration('us'))
  2. Normalize at the source: keep all upstream datetimes in a single time unit so derived durations share it

Example fix

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

# after
d1 = df1["dur"].cast(pl.Duration("us")).get(0)
d2 = df2["dur"].cast(pl.Duration("us")).get(0)
cmp = d1 < d2
Defensive patterns

Strategy: validation

Validate before calling

def durations_comparable(a: pl.Series, b: pl.Series) -> bool:
    return (
        isinstance(a.dtype, pl.Duration) and isinstance(b.dtype, pl.Duration)
        and a.dtype.time_unit == b.dtype.time_unit
    )

Type guard

def aligned_duration(s: pl.Series, unit: str = "us") -> pl.Series:
    return s.cast(pl.Duration(unit))

Prevention

When it happens

Trigger: Comparing duration AnyValues from columns of different dtypes: Duration('ms') vs Duration('us'), e.g. df1["d"].get(0) < df2["d"].get(0) after diff/subtract operations that produced different units.

Common situations: Durations derived from datetime columns with mismatched units (subtractions of ms vs us timestamps), or comparing parsed durations against literals with a different unit.

Related errors


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