pandas-dev/pandas · error · TypeError
Cannot use .astype to convert from timezone-aware dtype to t
Error message
Cannot use .astype to convert from timezone-aware dtype to timezone-naive dtype. Use obj.tz_localize(None) or obj.tz_convert('UTC').tz_localize(None) instead. What it means
Raised by DatetimeArray.astype (and DatetimeIndex.astype) when you call .astype() on a timezone-aware datetime array/index and request a plain numpy 'datetime64' (tz-naive) target dtype. astype cannot silently drop timezone information because that would be a lossy, ambiguous conversion. Pandas requires you to explicitly choose how to drop the tz via tz_localize(None) (keep wall time) or tz_convert('UTC').tz_localize(None) (keep UTC instant).
Source
Thrown at pandas/core/arrays/datetimes.py:731
res_values = astype_overflowsafe(self._ndarray, np_dtype, copy=copy)
return type(self)._simple_new(res_values, dtype=dtype)
elif (
self.tz is None
and lib.is_np_dtype(dtype, "M")
and not is_unitless(dtype)
and is_supported_dtype(dtype)
):
# unit conversion e.g. datetime64[s]
res_values = astype_overflowsafe(self._ndarray, dtype, copy=True)
return type(self)._simple_new(res_values, dtype=res_values.dtype)
# TODO: preserve freq?
elif self.tz is not None and lib.is_np_dtype(dtype, "M"):
# pre-2.0 behavior for DTA/DTI was
# values.tz_convert("UTC").tz_localize(None), which did not match
# the Series behavior
raise TypeError(
"Cannot use .astype to convert from timezone-aware dtype to "
"timezone-naive dtype. Use obj.tz_localize(None) or "
"obj.tz_convert('UTC').tz_localize(None) instead."
)
elif (
self.tz is None
and lib.is_np_dtype(dtype, "M")
and dtype != self.dtype
and is_unitless(dtype)
):
raise TypeError(
"Casting to unit-less dtype 'datetime64' is not supported. "
"Pass e.g. 'datetime64[ns]' instead."
)
elif isinstance(dtype, PeriodDtype):
return self.to_period(freq=dtype.freq)View on GitHub (pinned to 3b7651241d)
Solutions
- If you want to preserve the UTC instant: `obj.tz_convert('UTC').tz_localize(None)`.
- If you want to keep the wall-clock values and just drop tz: `obj.tz_localize(None)`.
- If you wanted to change units on a tz-aware array, pass a DatetimeTZDtype target like `obj.astype('datetime64[s, US/Eastern]')` instead of a tz-naive one.
- For DataFrame/Series columns, operate via `.dt` accessor: `s.dt.tz_localize(None)` or `s.dt.tz_convert('UTC').dt.tz_localize(None)`.
Example fix
// before
df['ts'] = df['ts'].astype('datetime64[ns]') # ts is tz-aware
// after
df['ts'] = df['ts'].dt.tz_convert('UTC').dt.tz_localize(None) Defensive patterns
Strategy: validation
Validate before calling
import pandas as pd
def to_tz_naive(obj):
if getattr(obj.dtype, 'tz', None) is not None:
return obj.dt.tz_convert('UTC').dt.tz_localize(None)
return obj Type guard
def is_tz_aware(obj) -> bool:
dt = getattr(obj, 'dtype', None)
return getattr(dt, 'tz', None) is not None Try / catch
try:
out = col.astype('datetime64[ns]')
except TypeError as e:
if 'timezone-aware dtype to timezone-naive' in str(e):
out = col.dt.tz_convert('UTC').dt.tz_localize(None)
else:
raise Prevention
- Audit every `.astype('datetime64...')` call against tz-aware data when migrating to pandas 2.x.
- Centralize tz handling in one helper rather than dropping tz inline at multiple call sites.
- Prefer the `.dt.tz_*` accessors over astype for any tz operation.
When it happens
Trigger: Calling `tz_aware_dti.astype('datetime64[ns]')` or `tz_aware_series.astype('datetime64[ns]')` where the source has a DatetimeTZDtype (e.g. datetime64[ns, US/Eastern]) and the target dtype has no tz. Also triggered by `astype(np.dtype('M8[ns]'))` on a tz-aware DTA.
Common situations: Downstream code that stripped tz via astype in pandas <2.0 (the pre-2.0 behavior silently did tz_convert('UTC').tz_localize(None)); migrating to pandas 2.x without updating these calls. Passing data into libraries that dislike tz-aware columns (e.g. numpy-only ML pipelines) and reaching for astype out of habit.
Related errors
- Casting to unit-less dtype 'datetime64' is not supported. Pa
- cannot supply both a tz and a dtype with a tz
- Cannot pass both a timezone-aware dtype and tz=None
- cannot supply both a tz and a timezone-naive dtype (i.e. dat
- Passed data is timezone-aware, incompatible with 'tz=None'.
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/d2f272ff50aba5fa.
Report an issue: GitHub.