pandas-dev/pandas · error · TypeError

DatetimeIndex has mixed timezones

Error message

DatetimeIndex has mixed timezones

What it means

Raised inside datetime._sequence_to_dt64/parse-related path when the values parse as datetimes but yield an object-dtype array (meaning some elements carry tz info and others do not, or they carry conflicting tz), and the caller disallowed object output (allow_object=False). The mixed-awareness result cannot be unified into a single datetime64[ns] or datetime64[ns, tz] dtype. GH#23675.

Solutions

  1. Normalize all source timestamps to a single tz before constructing the index: `[ts.tz_convert('UTC') if ts.tzinfo else ts.tz_localize('UTC') for ts in values]`.
  2. Strip tz from all of them: `[ts.tz_localize(None) if ts.tzinfo else ts for ts in values]`.
  3. If mixed awareness is genuinely desired, keep the column as object dtype and avoid DatetimeIndex.
  4. Validate at ingest: enforce a single tz policy at the data-source boundary.

Example fix

// before
dti = pd.DatetimeIndex(mixed_ts_list)

// after
normalized = [ts.tz_convert('UTC') if ts.tzinfo else ts.tz_localize('UTC') for ts in mixed_ts_list]
dti = pd.DatetimeIndex(normalized)
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd

def normalize_to_single_tz(timestamps, target='UTC'):
    out = []
    for ts in timestamps:
        ts = pd.Timestamp(ts)
        if ts.tzinfo is None:
            ts = ts.tz_localize(target)
        else:
            ts = ts.tz_convert(target)
        out.append(ts)
    return out

Type guard

def all_same_awareness(timestamps) -> bool:
    aware = [pd.Timestamp(t).tzinfo is not None for t in timestamps]
    return all(aware) or not any(aware)

Try / catch

try:
    dti = pd.DatetimeIndex(values)
except TypeError as e:
    if 'mixed timezones' in str(e):
        values = normalize_to_single_tz(values)
        dti = pd.DatetimeIndex(values)
    else:
        raise

Prevention

When it happens

Trigger: Constructing `pd.DatetimeIndex([ts1_utc, ts2_naive, ts3_est])`, or calling `pd.to_datetime(...)` with mixed-aware timestamps when the caller forbids object fallback. Reading a column whose rows came from sources with different tz conventions.

Common situations: Concatenating Timestamps produced by `pd.Timestamp.now(tz=...)` and `pd.Timestamp.now()` in the same column. JSON/dict ingestion where some records include offsets and others do not. Database pulls mixing aware/naive across rows.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/f8e4dcdcfae46166. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/datetimes.py:2860

        yearfirst=yearfirst,
        creso=abbrev_to_npy_unit(out_unit),
    )

    if tz_parsed is not None:
        # We can take a shortcut since the datetime64 numpy array
        #  is in UTC
        return result, tz_parsed
    elif result.dtype.kind == "M":
        return result, tz_parsed
    elif result.dtype == object:
        # GH#23675 when called via `pd.to_datetime`, returning an object-dtype
        #  array is allowed.  When called via `pd.DatetimeIndex`, we can
        #  only accept datetime64 dtype, so raise TypeError if object-dtype
        #  is returned, as that indicates the values can be recognized as
        #  datetimes but they have conflicting timezones/awareness
        if allow_object:
            return result, tz_parsed
        raise TypeError("DatetimeIndex has mixed timezones")
    else:  # pragma: no cover
        # GH#23675 this TypeError should never be hit, whereas the TypeError
        #  in the object-dtype branch above is reachable.
        raise TypeError(result)


def maybe_convert_dtype(data, copy: bool, tz: tzinfo | None = None):
    """
    Convert data based on dtype conventions, issuing
    errors where appropriate.

    Parameters
    ----------
    data : np.ndarray or pd.Index
    copy : bool
    tz : tzinfo or None, default None

    Returns

View on GitHub (pinned to 3b7651241d)