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

  1. Keep time components two-digit: '12:30:05' or '123005'
  2. Truncate at component boundaries, never mid-string: build output from dt.strftime('%H:%M') instead of slicing
  3. 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

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


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/5aa75de388da79aa. Report an issue: GitHub.