python/cpython · error · TypeError
tz argument must be an instance of tzinfo
Error message
tz argument must be an instance of tzinfo
What it means
datetime.astimezone(tz) requires tz to be a tzinfo instance (or None, which selects the local timezone). Any other value — string zone name, int offset, ZoneInfo-less code path — triggers this TypeError before any conversion happens.
Source
Thrown at Lib/_pydatetime.py:2131
ts = self._mktime()
# Detect gap
ts2 = self.replace(fold=1-self.fold)._mktime()
if ts2 != ts: # This happens in a gap or a fold
if (ts2 > ts) == self.fold:
ts = ts2
else:
ts = (self - _EPOCH) // timedelta(seconds=1)
localtm = _time.localtime(ts)
# Extract TZ data
gmtoff = localtm.tm_gmtoff
zone = localtm.tm_zone
return timezone(timedelta(seconds=gmtoff), zone)
def astimezone(self, tz=None):
if tz is None:
tz = self._local_timezone()
elif not isinstance(tz, tzinfo):
raise TypeError("tz argument must be an instance of tzinfo")
mytz = self.tzinfo
if mytz is None:
mytz = self._local_timezone()
myoffset = mytz.utcoffset(self)
else:
myoffset = mytz.utcoffset(self)
if myoffset is None:
mytz = self.replace(tzinfo=None)._local_timezone()
myoffset = mytz.utcoffset(self)
if tz is mytz:
return self
# Convert self to UTC, and attach the new time zone object.
utc = (self - myoffset).replace(tzinfo=tz)
# Convert from UTC to tz's local time.View on GitHub (pinned to bc6749cc3b)
Solutions
- Convert string names: dt.astimezone(ZoneInfo('US/Eastern'))
- Wrap fixed offsets: dt.astimezone(timezone(timedelta(hours=2)))
- For UTC use dt.astimezone(timezone.utc)
- Check for shadowed imports of timezone/ZoneInfo in the module
Example fix
// before
dt = dt.astimezone('UTC')
# after
from zoneinfo import ZoneInfo
dt = dt.astimezone(ZoneInfo('UTC')) Defensive patterns
Strategy: type-guard
Validate before calling
from datetime import tzinfo
def as_tzinfo(tz):
if tz is None or isinstance(tz, tzinfo):
return tz
if isinstance(tz, str):
from zoneinfo import ZoneInfo
return ZoneInfo(tz)
raise TypeError(f'cannot interpret {tz!r} as a timezone') Type guard
from datetime import tzinfo
def is_tzinfo(v) -> bool:
return v is None or isinstance(v, tzinfo) Prevention
- Store zone names in config but convert via ZoneInfo at load
- Standardize on timezone.utc for UTC
- Never pass raw offsets — wrap in timezone(timedelta(...))
When it happens
Trigger: dt.astimezone('UTC'), dt.astimezone(0), or dt.astimezone(timezone.utc) where timezone was shadowed/not imported. Passing pytz timezone objects works (they are tzinfo subclasses), but raw strings never do.
Common situations: Config files storing TZ as a string ('US/Eastern') passed directly; forgetting to wrap offsets: astimezone(timedelta(hours=2)) instead of astimezone(timezone(timedelta(hours=2))); mixing up ZoneInfo('UTC') with the literal 'UTC'.
Related errors
- cannot compare naive and aware datetimes
- cannot mix naive and timezone-aware time
- offset must be a timedelta
- name must be a string
- type 'datetime.timezone' is not an acceptable base type
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/544aa4dff19e0eb4.
Report an issue: GitHub.