{"record":{"id":"3a56b92249d83d54","repo":"RustPython/RustPython","slug":"invalid-isoformat-string-time-string-r","errorCode":null,"errorMessage":"Invalid isoformat string: {time_string!r}","messagePattern":"Invalid isoformat string: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":1627,"sourceCode":"        return s\n\n    __str__ = isoformat\n\n    @classmethod\n    def fromisoformat(cls, time_string):\n        \"\"\"Construct a time from a string in one of the ISO 8601 formats.\"\"\"\n        if not isinstance(time_string, str):\n            raise TypeError('fromisoformat: argument must be str')\n\n        # The spec actually requires that time-only ISO 8601 strings start with\n        # T, but the extended format allows this to be omitted as long as there\n        # is no ambiguity with date strings.\n        time_string = time_string.removeprefix('T')\n\n        try:\n            return cls(*_parse_isoformat_time(time_string)[0])\n        except Exception:\n            raise ValueError(f'Invalid isoformat string: {time_string!r}')\n\n    def strftime(self, format):\n        \"\"\"Format using strftime().  The date part of the timestamp passed\n        to underlying strftime should not be used.\n        \"\"\"\n        # The year must be >= 1000 else Python's strftime implementation\n        # can raise a bogus exception.\n        timetuple = (1900, 1, 1,\n                     self._hour, self._minute, self._second,\n                     0, 1, -1)\n        return _wrap_strftime(self, format, timetuple)\n\n    def __format__(self, fmt):\n        if not isinstance(fmt, str):\n            raise TypeError(\"must be str, not %s\" % type(fmt).__name__)\n        if len(fmt) != 0:\n            return self.strftime(fmt)\n        return str(self)","sourceCodeStart":1609,"sourceCodeEnd":1645,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pydatetime.py#L1609-L1645","documentation":"time.fromisoformat() could not parse the string: after stripping an optional leading 'T', _parse_isoformat_time failed to consume it as HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]. Any leftover character, missing or non-padded component, out-of-range value, or wrong separator ends here, and the offending string is embedded in the message.","triggerScenarios":"time.fromisoformat('9:00') (single-digit hour); '12-30' (dash separator); '25:00' (hour out of range); '12:00:00+99:00' (bad offset); '12:00:00 ' (trailing space); fractional-second formats the running Python version does not accept.","commonSituations":"User-supplied times without strict validation; logs or exports with locale-formatted times ('1.30pm'); spreadsheets and CSVs with padded or partial strings; inputs that look ISO-ish but use different separators.","solutions":["Validate or normalize shape before parsing: strip whitespace, zero-pad components.","Use time.strptime(s, '%H:%M:%S') matching the format you actually receive when it is not ISO.","Wrap parsing per field and report which value failed instead of letting the error bubble.","Enforce an ISO-shape regex at the API boundary."],"exampleFix":"// before\nt = time.fromisoformat(raw)  # raw == '9:05' -> ValueError\n\n// after\nimport re\nraw = raw.strip()\nif not re.fullmatch(r'\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?', raw):\n    raise ValueError(f'expected HH:MM[:SS[.f]], got {raw!r}')\nt = time.fromisoformat(raw)","handlingStrategy":"try-catch","validationCode":"import re\nfrom datetime import time\n\nISO_TIME = re.compile(r'\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,6})?)?([+-]\\d{2}:\\d{2}(:\\d{2}(\\.\\d{1,6})?)?|Z)?')\n\ndef looks_like_iso_time(s: str) -> bool:\n    return ISO_TIME.fullmatch(s.strip()) is not None","typeGuard":null,"tryCatchPattern":"from datetime import time\n\ndef parse_time_field(s: str):\n    try:\n        return time.fromisoformat(s.strip())\n    except ValueError:\n        raise ValueError(f'bad time field {s!r}: expected HH:MM[:SS[.ffffff]]') from None","preventionTips":["Zero-pad and strip time strings before fromisoformat.","Use strptime with an explicit format for non-ISO inputs.","Catch ValueError per field in ETL and keep the raw string in the error report.","Reject locale-style times ('1.30pm') at the API boundary."],"tags":["datetime","time","fromisoformat","iso8601","valueerror","parse-error"],"backgroundTag":"invalid-isoformat-string","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}