{"record":{"id":"03597db1c23a126c","repo":"RustPython/RustPython","slug":"fromutc-requires-a-non-none-utcoffset-result","errorCode":null,"errorMessage":"fromutc() requires a non-None utcoffset() result","messagePattern":"fromutc\\(\\) requires a non-None utcoffset\\(\\) result","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":1325,"sourceCode":"    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\")\n        if dt.tzinfo is not self:\n            raise ValueError(\"dt.tzinfo is not self\")\n\n        dtoff = dt.utcoffset()\n        if dtoff is None:\n            raise ValueError(\"fromutc() requires a non-None utcoffset() \"\n                             \"result\")\n\n        # See the long comment block at the end of this file for an\n        # explanation of this algorithm.\n        dtdst = dt.dst()\n        if dtdst is None:\n            raise ValueError(\"fromutc() requires a non-None dst() result\")\n        delta = dtoff - dtdst\n        if delta:\n            dt += delta\n            dtdst = dt.dst()\n            if dtdst is None:\n                raise ValueError(\"fromutc(): dt.dst gave inconsistent \"\n                                 \"results; cannot convert\")\n        return dt + dtdst\n\n    # Pickle support.\n","sourceCodeStart":1307,"sourceCodeEnd":1343,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pydatetime.py#L1307-L1343","documentation":"The fromutc() algorithm needs dt.utcoffset() to compute the gap between UTC and the zone's standard time. If the attached tzinfo answers None — the convention for 'offset unknown', and what broken or half-implemented zones return — the conversion cannot proceed and raises this ValueError.","triggerScenarios":"tz.fromutc(dt) where dt.tzinfo.utcoffset(dt) returns None; a custom tzinfo whose utcoffset() has a None code path for some datetimes; zones that refuse offsets for pre-transition or ambiguous times.","commonSituations":"Custom tzinfo subclasses modeled on doc examples where utcoffset returns None by default; pipelines attaching half-implemented zones; porting code that assumed an offset always exists for aware datetimes.","solutions":["Use astimezone() with concrete zones (datetime.timezone, zoneinfo) that always report an offset.","Make the custom utcoffset() return a timedelta for every datetime fromutc() will see; reserve None strictly for 'unknown'.","Check dt.utcoffset() is not None before calling tz.fromutc(dt)."],"exampleFix":"// before\nresult = my_tz.fromutc(dt)  # my_tz.utcoffset(dt) returned None\n\n// after\nif dt.utcoffset() is None:\n    raise ValueError(f'{my_tz!r} reports no offset for {dt}')\nresult = dt.astimezone(my_tz)","handlingStrategy":"validation","validationCode":"def fromutc_safe(tz, dt):\n    if dt.tzinfo is not tz:\n        dt = dt.replace(tzinfo=tz)\n    if dt.utcoffset() is None:\n        raise ValueError(f'{tz!r} reports no utcoffset for {dt}')\n    return tz.fromutc(dt)","typeGuard":null,"tryCatchPattern":"try:\n    local = tz.fromutc(dt)\nexcept ValueError:\n    local = dt.replace(tzinfo=timezone.utc).astimezone(tz)  # concrete-zone fallback","preventionTips":["Verify dt.utcoffset() is not None before calling fromutc().","Custom utcoffset() should return a timedelta, reserving None for 'unknown'.","Prefer timezone/zoneinfo zones that always report offsets."],"tags":["datetime","tzinfo","fromutc","utcoffset","valueerror"],"backgroundTag":"fromutc-precondition-violation","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}