pola-rs/polars · error · TypeError

time zone of dtype ( ) differs from time zone of value ( )

Error message

time zone of dtype ({dtype_tz!r}) differs from time zone of value ({value_tz!r})

What it means

`pl.lit` was given a tz-aware datetime and a `Datetime` dtype whose time zone differs from the value's time zone. Polars will not silently reinterpret time zones, so it raises rather than producing shifted timestamps.

Solutions

  1. Make the dtype time zone match the value's, e.g. `pl.Datetime('us', 'UTC')` for a UTC-aware value
  2. Convert the value first: `value.astimezone(zoneinfo.ZoneInfo(dtype_tz))`
  3. Use a tz-naive dtype + `dt.replace_time_zone` on the resulting expression if you want wall-clock semantics

Example fix

// before
pl.lit(dt_paris, dtype=pl.Datetime('us', 'UTC'))
// after
pl.lit(dt_paris.astimezone(ZoneInfo('Europe/Paris')), dtype=pl.Datetime('us', 'Europe/Paris'))
Defensive patterns

Strategy: validation

Validate before calling

value_tz = str(value.tzinfo) if value.tzinfo else None
if value_tz and dtype.time_zone and value_tz != dtype.time_zone:
    value = value.astimezone(ZoneInfo(dtype.time_zone))

Type guard

def tz_matches(value, dtype) -> bool:
    return value.tzinfo is None or dtype.time_zone is None or str(value.tzinfo) == dtype.time_zone

Try / catch

try:
    expr = pl.lit(value, dtype=dt_dtype)
except TypeError as e:
    if 'time zone of dtype' in str(e):
        value = value.astimezone(ZoneInfo(dt_dtype.time_zone))
        expr = pl.lit(value, dtype=dt_dtype)
    else:
        raise

Prevention

When it happens

Trigger: `pl.lit(datetime_with_tz, dtype=pl.Datetime('us', 'Other/Zone'))` where the Python datetime's `tzinfo` resolves to a different zone name than the dtype's `time_zone`.

Common situations: Mixing 'UTC' with a named zone like 'Europe/Paris'; building literals from user-supplied datetimes with arbitrary tzinfo; DST-related code that swaps tzinfo.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/a3b1c12f0865370c. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/functions/lit.py:155

                    value = value.astimezone(timezone.utc)
                    tz = "UTC"

            # dtype and value both have same time zone
            elif str(value_tz) == dtype_tz:
                tz = str(value_tz)

            # given a fixed offset from UTC that matches the dtype tz offset
            elif hasattr(value_tz, "utcoffset") and getattr(
                ZoneInfo(dtype_tz).utcoffset(value), "seconds", 0
            ) == getattr(value_tz.utcoffset(value), "seconds", 1):
                tz = dtype_tz
            else:
                # value has time zone that differs from dtype time zone
                msg = (
                    f"time zone of dtype ({dtype_tz!r}) differs from time zone of "
                    f"value ({value_tz!r})"
                )
                raise TypeError(msg)

        dt_utc = value.replace(tzinfo=timezone.utc)
        dt_utc_s = pl.Series("literal", [dt_utc]).cast(Datetime(time_unit))
        if tz is not None:
            dt_utc_s = dt_utc_s.dt.replace_time_zone(
                tz, ambiguous="earliest" if value.fold == 0 else "latest"
            )
        expr = wrap_expr(plr.lit(dt_utc_s._s, allow_object=False, is_scalar=True))
        return expr

    elif isinstance(value, timedelta):
        value_s = pl.Series("literal", [value])
        if dtype is not None and (tu := getattr(dtype, "time_unit", None)) is not None:
            tu = cast("TimeUnit", tu)
            value_s = value_s.cast(Duration(tu))
        expr = wrap_expr(plr.lit(value_s._s, allow_object=False, is_scalar=True))
        return expr

View on GitHub (pinned to fe841f959e)