python/cpython · error · ValueError
fromutc: dt.tzinfo is not self
Error message
fromutc: dt.tzinfo is not self
What it means
timezone.fromutc(dt) converts a UTC-wall-clock datetime into local time by adding the fixed offset — but only when dt.tzinfo is exactly this timezone instance. Passing a datetime attached to a different tzinfo object (even an equal-offset one) raises ValueError, because fromutc would otherwise produce a datetime labeled with the wrong zone.
Source
Thrown at Lib/_pydatetime.py:2537
def tzname(self, dt):
if isinstance(dt, datetime) or dt is None:
if self._name is None:
return self._name_from_offset(self._offset)
return self._name
raise TypeError("tzname() argument must be a datetime instance"
" or None")
def dst(self, dt):
if isinstance(dt, datetime) or dt is None:
return None
raise TypeError("dst() argument must be a datetime instance"
" or None")
def fromutc(self, dt):
if isinstance(dt, datetime):
if dt.tzinfo is not self:
raise ValueError("fromutc: dt.tzinfo "
"is not self")
return dt + self._offset
raise TypeError("fromutc() argument must be a datetime instance"
" or None")
_maxoffset = timedelta(hours=24, microseconds=-1)
_minoffset = -_maxoffset
@staticmethod
def _name_from_offset(delta):
if not delta:
return 'UTC'
if delta < timedelta(0):
sign = '-'
delta = -delta
else:
sign = '+'
hours, rest = divmod(delta, timedelta(hours=1))View on GitHub (pinned to bc6749cc3b)
Solutions
- Attach the zone first: tz.fromutc(dt.replace(tzinfo=tz))
- Prefer the public API: dt.astimezone(tz) handles attachment and fromutc correctly
- Ensure helper functions rebind tzinfo rather than assuming it is already set
Example fix
// before local = my_tz.fromutc(utc_dt) # utc_dt.tzinfo is timezone.utc # after local = utc_dt.astimezone(my_tz)
Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime
def from_utc(tz, dt: datetime) -> datetime:
if dt.tzinfo is not tz:
dt = dt.replace(tzinfo=tz)
return tz.fromutc(dt) Type guard
def is_bound_to(dt, tz) -> bool:
return dt.tzinfo is tz Try / catch
try:
local = tz.fromutc(dt)
except ValueError:
local = dt.astimezone(tz) # public API handles binding Prevention
- Prefer dt.astimezone(tz) over direct fromutc calls
- Rebind tzinfo with replace() before manual fromutc
- Check dt.tzinfo is tz before protocol-level conversion
When it happens
Trigger: utc_tz.fromutc(dt) where dt.tzinfo is timezone.utc or another timezone instance; datetime.astimezone internally relies on fromutc with self-attached datetimes, so direct misuse is the usual trigger; reusing datetimes across zone objects.
Common situations: Manual UTC→local conversions that forget dt.replace(tzinfo=tz); caching converted datetimes and re-running fromutc on them; helper functions receiving datetimes already bound to another zone.
Related errors
- fromutc() argument must be a datetime instance or None
- minute, second, and microsecond must be 0 when hour is 24
- tz argument must be an instance of tzinfo
- cannot compare naive and aware datetimes
- cannot mix naive and timezone-aware time
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/9d3965876df67dda.
Report an issue: GitHub.