python/cpython · error · ValueError

Invalid time separator: %c

Error message

Invalid time separator: %c

What it means

In _parse_hh_mm_ss_ff, once the first component pair established whether separators are colons (has_sep from 'HH:'), every subsequent separator must also be ':' or absent. A different character (e.g. '12:30-05') raises ValueError('Invalid time separator: -') with the offending character interpolated.

Source

Thrown at Lib/_pydatetime.py:420

    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:
        if tstr[pos] not in '.,':
            raise ValueError("Invalid microsecond separator")
        else:
            pos += 1
            if not all(map(_is_ascii_digit, tstr[pos:])):
                raise ValueError("Non-digit values in fraction")

            len_remainder = len_str - pos

            if len_remainder >= 6:
                to_parse = 6
            else:
                to_parse = len_remainder

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Use ':' between all time components (or no separators at all: '123005')
  2. Sanitize with a targeted regex: re.sub(r'^(\d{2}):(\d{2})-(\d{2})$', r'\1:\2:\3', s)
  3. Parse flexible input with datetime.strptime(s, '%H-%M-%S') or dateutil instead of fromisoformat

Example fix

// before
dt = datetime.fromisoformat('2021-01-01T12:30-05')  # ValueError

# after
import re
s = re.sub(r'(?<=\d\d)-(\d\d)$', r':\1', raw)
dt = datetime.fromisoformat(s)
Defensive patterns

Strategy: validation

Validate before calling

import re
def fix_time_separators(t: str) -> str:
    return re.sub(r'(?<=\d\d)[^\d:.,+\-Zz]', ':', t)

Type guard

def has_valid_time_separators(t: str) -> bool:
    import re
    return re.fullmatch(r'\d{2}(:?\d{2}(:?\d{2}([.,]\d{1,6})?)?)?', t) is not None

Prevention

When it happens

Trigger: datetime.fromisoformat('2021-01-01T12:30-05'); time strings using '.', ' ' or '-' between minute and seconds; replacing 'T' with a space but also mangling colons during sanitization.

Common situations: Logs that use 'HH:MM-SS' formats; user-typed times with dashes; string replace('T',' ') pipelines that accidentally replace ':' elsewhere; locale time formats fed to fromisoformat.

Related errors


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