pandas-dev/pandas · error · TypeError
Cannot convert tz-naive timestamps, use tz_localize to…
Error message
Cannot convert tz-naive timestamps, use tz_localize to localize
What it means
Raised by DatetimeArray.tz_convert when self.tz is None. tz_convert is for changing from one tz to another and presupposes that the wall times are anchored to UTC; for tz-naive data that anchor does not exist, so you must first attach one via tz_localize. The docstring example shows the expected tz-aware usage.
Solutions
- Use tz_localize first to attach the source tz, then tz_convert: `s.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')`.
- If you know the source wall time was already UTC: `s.dt.tz_localize('UTC')` (and stop if that is the desired output).
- Check awareness before calling: `if s.dt.tz is None: s = s.dt.tz_localize('UTC')`.
Example fix
// before
s = pd.to_datetime(df['ts']).dt.tz_convert('US/Eastern')
// after
s = pd.to_datetime(df['ts']).dt.tz_localize('UTC').dt.tz_convert('US/Eastern') Defensive patterns
Strategy: validation
Validate before calling
import pandas as pd
def convert_tz(series, target):
if series.dt.tz is None:
series = series.dt.tz_localize('UTC')
return series.dt.tz_convert(target) Type guard
def is_tz_aware_series(s) -> bool:
return getattr(getattr(s, 'dtype', None), 'tz', None) is not None Try / catch
try:
out = s.dt.tz_convert(target)
except TypeError as e:
if 'tz-naive' in str(e):
out = s.dt.tz_localize('UTC').dt.tz_convert(target)
else:
raise Prevention
- Wrap tz conversion in a single helper that localizes-then-converts.
- After read_csv, immediately decide and apply a tz policy.
When it happens
Trigger: Calling `naive_dti.tz_convert('US/Eastern')`, `naive_series.dt.tz_convert('UTC')`, or any tz_convert on data whose `.dt.tz` is None. Common when reading CSV (which yields naive datetime64) and immediately trying to convert to a business tz.
Common situations: Loading a CSV with `pd.read_csv(parse_dates=[...])` yields tz-naive data; calling tz_convert instead of tz_localize. Assuming to_datetime gives UTC-anchored data (it does not — it gives naive wall times).
Related errors
- Already tz-aware, use tz_convert to convert.
- Passed data is timezone-aware, incompatible with 'tz=None'…
- Cannot compare tz-naive and tz-aware datetime-like objects.
- Cannot compare tz-naive and tz-aware datetime-like objects
- Cannot pass both a timezone-aware dtype and tz=None
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/d760087ddc054a9f.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/datetimes.py:944
... )
>>> dti
DatetimeIndex(['2014-08-01 09:00:00+02:00',
'2014-08-01 10:00:00+02:00',
'2014-08-01 11:00:00+02:00'],
dtype='datetime64[us, Europe/Berlin]', freq='h')
>>> dti.tz_convert(None)
DatetimeIndex(['2014-08-01 07:00:00',
'2014-08-01 08:00:00',
'2014-08-01 09:00:00'],
dtype='datetime64[us]', freq='h')
""" # noqa: E501
tz = timezones.maybe_get_tz(tz)
if self.tz is None:
# tz naive, use tz_localize
raise TypeError(
"Cannot convert tz-naive timestamps, use tz_localize to localize"
)
# No conversion since timestamps are all UTC to begin with
dtype = tz_to_dtype(tz, unit=self.unit)
return self._simple_new(self._ndarray, dtype=dtype)
@dtl.ravel_compat
def tz_localize(
self,
tz,
ambiguous: TimeAmbiguous = "raise",
nonexistent: TimeNonexistent = "raise",
) -> Self:
"""
Localize tz-naive Datetime Array/Index to tz-aware Datetime Array/Index.
This method takes a time zone (tz) naive Datetime Array/Index objectView on GitHub (pinned to 3b7651241d)