python/cpython · error · ValueError
Incomplete time component
Error message
Incomplete time component
What it means
The time parser _parse_hh_mm_ss_ff reads exactly two digits per component (HH, MM, SS). If fewer than two characters remain for the component being parsed, it raises ValueError('Incomplete time component') — e.g. a lone trailing '1' after a separator ('12:3' parsed in two-digit steps at the wrong offset, '12:30:5' style truncations depending on separator handling).
Source
Thrown at Lib/_pydatetime.py:406
pos += has_sep
day = int(dtstr[pos:pos + 2])
return [year, month, day]
_FRACTION_CORRECTION = [100000, 10000, 1000, 100, 10]
def _parse_hh_mm_ss_ff(tstr):
# Parses things of the form HH[:?MM[:?SS[{.,}fff[fff]]]]
len_str = len(tstr)
time_comps = [0, 0, 0, 0]
pos = 0
for comp in range(0, 3):
if (len_str - pos) < 2:
raise ValueError("Incomplete time component")
time_comps[comp] = int(tstr[pos:pos+2])
pos += 2
next_char = tstr[pos:pos+1]
if comp == 0:
has_sep = next_char == ':'
if not next_char or comp >= 2:
break
if has_sep and next_char != ':':
raise ValueError("Invalid time separator: %c" % next_char)
pos += has_sep
if pos < len_str:View on GitHub (pinned to bc6749cc3b)
Solutions
- Keep time components two-digit: '12:30:05' or '123005'
- Truncate at component boundaries, never mid-string: build output from dt.strftime('%H:%M') instead of slicing
- For sub-minute precision use strftime('%H:%M:%S') or isoformat(timespec=...)
Example fix
// before s = raw[:16] # chops '05' to '5' dt = datetime.fromisoformat(s) # ValueError # after dt = datetime.fromisoformat(raw) short = dt.isoformat(timespec='minutes') # '2021-01-01T12:30'
Defensive patterns
Strategy: validation
Validate before calling
import re
_TIME_RE = re.compile(r'^\d{2}(:?\d{2}(:?\d{2}([.,]\d{1,6})?)?)?$')
def parse_time_part(t: str):
if not _TIME_RE.fullmatch(t):
raise ValueError(f'bad time component layout: {t!r}')
return t Type guard
def time_components_complete(t: str) -> bool:
body = re.split(r'[.,]', t)[0]
parts = re.split(r':?', body)
return all(len(p) == 2 for p in parts) and 1 <= len(parts) <= 3 Prevention
- Always two-digit-pad HH, MM, SS
- Truncate timestamps only via isoformat(timespec=...), never slicing
- Test parsers against minimum inputs ('T00', 'T0', empty)
When it happens
Trigger: datetime.fromisoformat('2021-01-01T12:3'); time strings sliced mid-component; fractional part mistakenly placed without separator so the digit budget shifts ('12305' lengths that leave one dangling digit).
Common situations: Truncating timestamps to save space (e.g. s[:15] chopping seconds); regex captures that grabbed a partial component; fixed-width log parsing with off-by-one offsets.
Related errors
- Invalid time separator: %c
- Isoformat time too short
- Invalid ISO string
- Invalid isoformat string
- Inconsistent use of dash separator
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/5aa75de388da79aa.
Report an issue: GitHub.