pandas-dev/pandas · error · TypeError
DatetimeIndex has mixed timezones
Error message
DatetimeIndex has mixed timezones
What it means
Raised when constructing a DatetimeIndex from object-dtype data whose elements resolve to datetimes but disagree on tz (some aware, some naive, or multiple tzs). pandas cannot pick one tz, so when allow_object is False (the DatetimeIndex path) it refuses. TypeError.
Source
Thrown at pandas/core/arrays/datetimes.py:2862
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
ReturnsView on GitHub (pinned to 71959b8cb9)
Solutions
- Normalize all elements to one tz before constructing, e.g. localize naive ones and tz_convert the rest to UTC.
- Split aware vs naive rows, localize/convert separately, then concatenate.
- At ingestion, enforce utc=True in pd.to_datetime so everything becomes UTC consistently.
Example fix
# before
pd.DatetimeIndex([pd.Timestamp('2020', tz='UTC'), pd.Timestamp('2021')])
# after
pd.DatetimeIndex([pd.Timestamp('2020', tz='UTC'), pd.Timestamp('2021').tz_localize('UTC')]) Defensive patterns
Strategy: validation
Validate before calling
def normalize_tzs(ts_list, target='UTC'):
out = []
for ts in ts_list:
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(ts_list) -> bool:
tzs = {pd.Timestamp(t).tzinfo is not None for t in ts_list}
return len(tzs) == 1 Prevention
- Enforce utc=True at pd.to_datetime for mixed inputs.
- Validate tz homogeneity before constructing a DatetimeIndex.
- Sanitize DB/JSON rows where tz presence varies.
When it happens
Trigger: pd.DatetimeIndex([...]) where the list mixes aware and naive Timestamps/datetime.datetime; pd.to_datetime on a Series of Python datetimes that include some with tzinfo and some without.
Common situations: Concatenating data from sources with inconsistent tz handling; JSON/DB rows where some rows carry tz and others don't; user input mixed with default datetime.now().
Related errors
- data is already tz-aware {inferred_tz}, unable to set specif
- Cannot compare tz-naive and tz-aware datetime-like objects.
- Cannot compare tz-naive and tz-aware datetime-like objects
- Cannot convert tz-naive timestamps, use tz_localize to local
- The nonexistent argument must be one of 'raise', 'NaT', 'shi
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/f8e4dcdcfae46166.
Report an issue: GitHub.