{"record":{"id":"d4da4cde9f27b5cc","repo":"RustPython/RustPython","slug":"isoformat-time-too-short","errorCode":null,"errorMessage":"Isoformat time too short","messagePattern":"Isoformat time too short","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":448,"sourceCode":"\n            len_remainder = len_str - pos\n\n            if len_remainder >= 6:\n                to_parse = 6\n            else:\n                to_parse = len_remainder\n\n            time_comps[3] = int(tstr[pos:(pos+to_parse)])\n            if to_parse < 6:\n                time_comps[3] *= _FRACTION_CORRECTION[to_parse-1]\n\n    return time_comps\n\ndef _parse_isoformat_time(tstr):\n    # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]\n    len_str = len(tstr)\n    if len_str < 2:\n        raise ValueError(\"Isoformat time too short\")\n\n    # This is equivalent to re.search('[+-Z]', tstr), but faster\n    tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1 or tstr.find('Z') + 1)\n    timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr\n\n    time_comps = _parse_hh_mm_ss_ff(timestr)\n\n    hour, minute, second, microsecond = time_comps\n    became_next_day = False\n    error_from_components = False\n    if (hour == 24):\n        if all(time_comp == 0 for time_comp in time_comps[1:]):\n            hour = 0\n            time_comps[0] = hour\n            became_next_day = True\n        else:\n            error_from_components = True\n","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pydatetime.py#L430-L466","documentation":"_parse_isoformat_time needs at least a two-digit hour to begin parsing; a time string shorter than 2 characters raises ValueError('Isoformat time too short') before any component work starts. It fires when a datetime string ends at (or right after) the date/time separator, leaving an empty or single-character time part.","triggerScenarios":"datetime.fromisoformat('2021-01-01T') (empty time part) or '2021-01-01T7' (single hour digit) — the time portion after the separator has len < 2.","commonSituations":"Truncated exports that cut the string at a fixed width; code that appends 'T' optimistically; user input where the time was never entered.","solutions":["Supply at least 'HH': '2021-01-01T07' (and prefer the full 'HH:MM' or 'HH:MM:SS')","Treat an empty time part as midnight explicitly: parse the date with date.fromisoformat and combine with time(0, 0)","Check len(timestr) >= 2 before calling fromisoformat on split parts"],"exampleFix":"# before\ndatetime.fromisoformat('2021-01-01T')  # Isoformat time too short\n\n# after\ndatetime.combine(date.fromisoformat('2021-01-01'), time(0, 0))","handlingStrategy":"validation","validationCode":"date_part, sep, time_part = s.partition('T')\nif sep and len(time_part) < 2:\n    # empty or 1-char time: treat as midnight instead of failing\n    dt = datetime.combine(date.fromisoformat(date_part), time(0, 0))\nelse:\n    dt = datetime.fromisoformat(s)","typeGuard":null,"tryCatchPattern":"try:\n    dt = datetime.fromisoformat(s)\nexcept ValueError as e:\n    if 'too short' in str(e):\n        dt = datetime.combine(date.fromisoformat(s.rstrip('T')), time(0, 0))\n    else:\n        raise","preventionTips":["Never emit a bare 'T' at the end of a datetime string","Require at least HH in your timestamp schema","Split date and time on 'T' and validate each half's length before combining"],"tags":["datetime","iso8601","fromisoformat","valueerror","parse-error","truncated-input"],"backgroundTag":"iso8601-parse-error","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}