python/cpython · error · NotImplementedError

tzinfo subclass must override dst()

Error message

tzinfo subclass must override dst()

What it means

Raised by the abstract base tzinfo.dst() when a timezone subclass does not override it. dst(dt) must return the daylight-saving offset as a timedelta (or zero/None when DST is not in effect); utcoffset() is expected to already include it. Any code path that asks a datetime for its DST state (e.g. the default fromutc algorithm) hits this stub on incomplete subclasses.

Solutions

  1. Override dst(self, dt) to return timedelta(0) for zones without DST
  2. Use datetime.timezone (fixed offset, DST-free by definition) or zoneinfo.ZoneInfo (full DST rules) instead of subclassing
  3. If overriding fromutc() yourself, ensure dst() is still defined for other callers

Example fix

// before
class MyTZ(tzinfo):
    def utcoffset(self, dt): return timedelta(hours=9)
    def tzname(self, dt): return 'JST'

// after
class MyTZ(tzinfo):
    def utcoffset(self, dt): return timedelta(hours=9)
    def tzname(self, dt): return 'JST'
    def dst(self, dt): return timedelta(0)
Defensive patterns

Strategy: validation

Validate before calling

assert type(tz).dst is not tzinfo.dst, 'dst() not overridden'
# also exercise the fromutc path used by astimezone
_ = datetime(2024, 1, 1, tzinfo=tz).astimezone(timezone.utc)

Type guard

def tz_has_dst(tz) -> bool:
    return type(tz).dst is not tzinfo.dst

Try / catch

try:
    _ = dt.dst()
except NotImplementedError:
    pass  # no DST info; skip DST-dependent logic

Prevention

When it happens

Trigger: class MyTZ(tzinfo): pass (or missing only dst) then datetime.now(MyTZ()).dst(); calling .astimezone() on a datetime attached to such a tzinfo, which invokes the default fromutc and its dst() call; direct MyTZ().dst(dt).

Common situations: Fixed-offset custom timezones where the author assumed dst() would never be called — but fromutc() and some formatting paths still invoke it; test doubles for tzinfo that implement only utcoffset.

Related errors


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

Appendix: source

Thrown at Lib/_pydatetime.py:1329

    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")
        if dt.tzinfo is not self:
            raise ValueError("dt.tzinfo is not self")

        dtoff = dt.utcoffset()
        if dtoff is None:
            raise ValueError("fromutc() requires a non-None utcoffset() "
                             "result")

        # See the long comment block at the end of this file for an
        # explanation of this algorithm.
        dtdst = dt.dst()
        if dtdst is None:

View on GitHub (pinned to bc6749cc3b)