python/cpython · error · ValueError

time data %r does not match format %r

Error message

time data %r does not match format %r

What it means

After compiling the format into a regex, _strptime runs format_regex.match(data_string); if the match fails entirely, this ValueError reports both the data and the format with %r reprs. It means the input string does not fit the format at the very first mismatching position.

Source

Thrown at Lib/_strptime.py:574

        format_regex = _regex_cache.get(format)
        if not format_regex:
            try:
                format_regex = _TimeRE_cache.compile(format)
            # KeyError raised when a bad format is found; can be specified as
            # \\, in which case it was a stray % but with a space after it
            except KeyError as err:
                bad_directive = err.args[0]
                del err
                bad_directive = bad_directive.replace('\\s', '')
                if not bad_directive:
                    raise ValueError("stray %% in format '%s'" % format) from None
                bad_directive = bad_directive.replace('\\', '', 1)
                raise ValueError("'%s' is a bad directive in format '%s'" %
                                    (bad_directive, format)) from None
            _regex_cache[format] = format_regex
    found = format_regex.match(data_string)
    if not found:
        raise ValueError("time data %r does not match format %r" %
                         (data_string, format))
    if len(data_string) != found.end():
        rest = data_string[found.end():]
        # Specific check for '%:z' directive
        if (
            "colon_z" in found.re.groupindex
            and found.group("colon_z") is not None
            and rest[0] != ":"
        ):
            raise ValueError(
                f"Missing colon in %:z before '{rest}', got '{data_string}'"
            )
        raise ValueError("unconverted data remains: %s" % rest)

    iso_year = year = None
    month = day = 1
    hour = minute = second = fraction = 0
    tz = -1

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Compare the reprs in the message to spot the first divergent field and fix the format (or the data)
  2. Strip the input: data.strip() before parsing
  3. For variable formats, try datetime.fromisoformat or dateutil.parser
  4. Normalize the input first (e.g. zfill parts, or re.split on separators)

Example fix

# before
>>> datetime.strptime('01-02-2020', '%Y-%m-%d')
ValueError: time data '01-02-2020' does not match format '%Y-%m-%d'

# after
>>> datetime.strptime('01-02-2020', '%d-%m-%Y')
datetime.datetime(2020, 2, 1, 0, 0)
Defensive patterns

Strategy: fallback

Validate before calling

from datetime import datetime

def try_parse(s: str, fmts):
    for f in fmts:
        try:
            return datetime.strptime(s.strip(), f)
        except ValueError:
            continue
    raise ValueError(f'unparseable date: {s!r}')

Try / catch

for fmt in ('%Y-%m-%d', '%d/%m/%Y', '%m/%d/%Y'):
    try:
        dt = datetime.strptime(s.strip(), fmt)
        break
    except ValueError:
        continue
else:
    raise ValueError(f'unparseable: {s!r}')

Prevention

When it happens

Trigger: datetime.strptime('2020-1-2', '%Y-%m-%d') can pass but '01-02-2020' with '%Y-%m-%d' fails; any case where literals, order, or directive values differ between data and format, e.g. strptime('12/31/99', '%Y-%m-%d') or 24-hour '25:00' with '%H'.

Common situations: Mixed source data (US vs ISO date order), zero-padded vs non-padded numbers, locale-dependent month names, AM/PM strings with %H, trailing whitespace/newline in the input.

Related errors


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