python/cpython · error · NotImplementedError

tzinfo subclass must override tzname()

Error message

tzinfo subclass must override tzname()

What it means

Raised by the abstract base tzinfo.tzname() when a timezone subclass does not override it. tzinfo is an interface: tzname(), utcoffset() and dst() must all be implemented by concrete subclasses. This error means someone instantiated/used a tzinfo subclass (including tzinfo itself) that left tzname() unimplemented.

Source

Thrown at Lib/_pydatetime.py:1317

        return (self.__class__, self._getstate())

_date_class = date  # so functions w/ args named "date" can get at the class

date.min = date(1, 1, 1)
date.max = date(9999, 12, 31)
date.resolution = timedelta(days=1)


class tzinfo:
    """Abstract base class for time zone info objects.

    Subclasses must override the tzname(), utcoffset() and dst() methods.
    """
    __slots__ = ()

    def tzname(self, dt):
        "datetime -> string name of time zone."
        raise NotImplementedError("tzinfo subclass must override tzname()")

    def utcoffset(self, dt):
        "datetime -> timedelta, positive for east of UTC, negative for west of UTC"
        raise NotImplementedError("tzinfo subclass must override utcoffset()")

    def dst(self, dt):
        """datetime -> DST offset as timedelta, positive for east of UTC.

        Return 0 if DST not in effect.  utcoffset() must include the DST
        offset.
        """
        raise NotImplementedError("tzinfo subclass must override dst()")

    def fromutc(self, dt):
        "datetime in UTC -> datetime in local time."

        if not isinstance(dt, datetime):
            raise TypeError("fromutc() requires a datetime argument")

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Override tzname(self, dt) in the subclass to return the zone name string (or None)
  2. Prefer the built-in datetime.timezone or zoneinfo.ZoneInfo instead of a hand-rolled tzinfo subclass
  3. If the method is intentionally unsupported, return None rather than inheriting the abstract stub

Example fix

// before
class MyTZ(tzinfo):
    def utcoffset(self, dt): return timedelta(hours=5)
    def dst(self, dt): return timedelta(0)

// after
class MyTZ(tzinfo):
    def utcoffset(self, dt): return timedelta(hours=5)
    def dst(self, dt): return timedelta(0)
    def tzname(self, dt): return 'UTC+05'
Defensive patterns

Strategy: validation

Validate before calling

for m in ('tzname', 'utcoffset', 'dst'):
    if type(tz).__getattribute__(type(tz), m) is getattr(tzinfo, m):
        raise TypeError(f'{type(tz).__name__} must implement {m}()')

Type guard

def is_complete_tzinfo(tz) -> bool:
    return all(getattr(type(tz), m, None) is not getattr(tzinfo, m)
               for m in ('tzname', 'utcoffset', 'dst'))

Try / catch

try:
    name = dt.tzname()
except NotImplementedError:
    name = None  # zone name unavailable; proceed without it

Prevention

When it happens

Trigger: class MyTZ(tzinfo): pass; then MyTZ().tzname(dt) — or any datetime with tz=MyTZ() calling .tzname(), or strftime('%Z') on such a datetime. Also calling tzinfo().tzname(dt) directly on the base class.

Common situations: Writing a custom timezone class for legacy regional rules and forgetting one of the three required methods; partially copy-pasted tzinfo subclasses from tutorials; migrating from pytz where method names differ.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/d5305f282ed5f50b. Report an issue: GitHub.