{"record":{"id":"f4bfe315c6c0990d","repo":"RustPython/RustPython","slug":"tzinfo-subclass-must-override-tzname","errorCode":null,"errorMessage":"tzinfo subclass must override tzname()","messagePattern":"tzinfo subclass must override tzname\\(\\)","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":1301,"sourceCode":"        return (self.__class__, self._getstate())\n\n_date_class = date  # so functions w/ args named \"date\" can get at the class\n\ndate.min = date(1, 1, 1)\ndate.max = date(9999, 12, 31)\ndate.resolution = timedelta(days=1)\n\n\nclass tzinfo:\n    \"\"\"Abstract base class for time zone info classes.\n\n    Subclasses must override the tzname(), utcoffset() and dst() methods.\n    \"\"\"\n    __slots__ = ()\n\n    def tzname(self, dt):\n        \"datetime -> string name of time zone.\"\n        raise NotImplementedError(\"tzinfo subclass must override tzname()\")\n\n    def utcoffset(self, dt):\n        \"datetime -> timedelta, positive for east of UTC, negative for west of UTC\"\n        raise NotImplementedError(\"tzinfo subclass must override utcoffset()\")\n\n    def dst(self, dt):\n        \"\"\"datetime -> DST offset as timedelta, positive for east of UTC.\n\n        Return 0 if DST not in effect.  utcoffset() must include the DST\n        offset.\n        \"\"\"\n        raise NotImplementedError(\"tzinfo subclass must override dst()\")\n\n    def fromutc(self, dt):\n        \"datetime in UTC -> datetime in local time.\"\n\n        if not isinstance(dt, datetime):\n            raise TypeError(\"fromutc() requires a datetime argument\")","sourceCodeStart":1283,"sourceCodeEnd":1319,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pydatetime.py#L1283-L1319","documentation":"tzinfo is an abstract base class: its tzname(), utcoffset() and dst() methods exist only to be overridden, and the base implementations raise NotImplementedError. This error means a bare tzinfo instance (or an incomplete subclass) was attached to a time/datetime and something asked it for a time-zone name via tzname(), directly or through strftime('%Z'). Use a concrete implementation such as datetime.timezone, zoneinfo.ZoneInfo, or a complete custom subclass.","triggerScenarios":"time(12, 0, tzinfo=tzinfo()).tzname(); datetime(..., tzinfo=tzinfo()).strftime('%Z'); a custom tzinfo subclass that overrides utcoffset() and dst() but not tzname(); a stub/mock tz left attached in place of the real zone.","commonSituations":"Placeholder tzinfo used while wiring up configuration; partial ports from pytz where the old class only implemented offsets; test doubles subclassing tzinfo with just enough to construct; tutorial code copied with tzinfo=tzinfo().","solutions":["Replace the bare tzinfo with a concrete zone: timezone.utc, timezone(timedelta(hours=n)), or zoneinfo.ZoneInfo('Region/City').","If it is your own subclass, implement tzname(self, dt) returning the display string (e.g. 'EST' or '+05:00').","For naive datetimes pass tzinfo=None instead of a dummy tzinfo.","Audit custom tzinfo classes to confirm all three of tzname/utcoffset/dst are overridden."],"exampleFix":"// before\nfrom datetime import time, tzinfo\nt = time(9, 30, tzinfo=tzinfo())  # later t.tzname() -> NotImplementedError\n\n// after\nfrom datetime import time, timedelta, timezone\nt = time(9, 30, tzinfo=timezone(timedelta(hours=5)))\nprint(t.tzname())  # 'UTC+05:00'","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"from datetime import tzinfo\n\ndef has_concrete_tzname(tz) -> bool:\n    if tz is None:\n        return True\n    if not isinstance(tz, tzinfo):\n        return False\n    try:\n        tz.tzname(None)\n    except NotImplementedError:\n        return False\n    return True","tryCatchPattern":"try:\n    name = dt.tzname()\nexcept NotImplementedError:\n    name = None  # or reattach timezone.utc / ZoneInfo before formatting","preventionTips":["Never instantiate the abstract tzinfo directly.","Prefer datetime.timezone or zoneinfo.ZoneInfo over hand-rolled subclasses.","When subclassing tzinfo, override tzname, utcoffset and dst together.","Assert tz is None or a known concrete type before attaching it."],"tags":["datetime","tzinfo","timezone","notimplementederror","abstract-class"],"backgroundTag":"abstract-method-not-implemented","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}