pola-rs/polars · error · TypeError

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

Error message

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

What it means

Raised by polars.lit when creating a datetime literal whose dtype carries a time zone that differs from the value's own tzinfo (and the value's offset does not coincidentally match the dtype tz offset at that instant). Polars refuses to silently reinterpret a zone; the zone on the value and on the Datetime dtype must agree.

Source

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

                    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 df599052da)

Solutions

  1. Convert the value to the dtype's zone first: value = value.astimezone(ZoneInfo(dtype_tz))
  2. Or make the dtype match the value's zone: Datetime('us', value.tzinfo key)
  3. Or drop the tz from the dtype and add it afterwards with dt.replace_time_zone / dt.convert_time_zone on the resulting expression

Example fix

// before
pl.lit(datetime(2024, 1, 1, tzinfo=ZoneInfo('Europe/Amsterdam')), dtype=Datetime('us', 'UTC'))
// after
pl.lit(datetime(2024, 1, 1, tzinfo=ZoneInfo('Europe/Amsterdam')).astimezone(ZoneInfo('UTC')), dtype=Datetime('us', 'UTC'))
Defensive patterns

Strategy: validation

Validate before calling

from datetime import datetime
from zoneinfo import ZoneInfo

def align_literal_tz(value: datetime, dtype):
    dtype_tz = getattr(dtype, 'time_zone', None)
    if dtype_tz is not None and value.tzinfo is not None:
        value_tz = value.tzinfo
        if str(value_tz) != dtype_tz:
            return value.astimezone(ZoneInfo(dtype_tz))
    return value

Type guard

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

Try / catch

try:
    e = pl.lit(dt, dtype=Datetime('us', 'UTC'))
except TypeError:
    e = pl.lit(dt.astimezone(ZoneInfo('UTC')), dtype=Datetime('us', 'UTC'))

Prevention

When it happens

Trigger: pl.lit(datetime(2024, 1, 1, tzinfo=ZoneInfo('Europe/Amsterdam')), dtype=Datetime('us', 'UTC')); mixing a timezone.utc value with a Datetime('us', 'America/New_York') dtype; passing a pytz/zoneinfo-aware datetime with a dtype tz from a different column schema.

Common situations: Hard-coding a dtype with a tz (e.g. copied from a schema dump) while user input datetimes carry local tzinfo; inconsistent tz handling between ingestion (UTC) and modeling (local tz); pytz-style localize vs zoneinfo conversions during migration.

Related errors


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