python/cpython · error · ValueError

Minute, second, and microsecond must be 0 when hour is 24

Error message

Minute, second, and microsecond must be 0 when hour is 24

What it means

Raised by time.fromisoformat() when the string uses hour 24 (ISO 8601 permits 24:00:00 to mean midnight at the end of a day) but minute, second, or microsecond are non-zero. The parser accepts hour 24 only for the exact end-of-day value; any additional time components make the value ambiguous/invalid, so a dedicated ValueError (instead of the generic 'Invalid isoformat string') is raised.

Source

Thrown at Lib/_pydatetime.py:1656

            raise TypeError('fromisoformat: argument must be str')

        # The spec actually requires that time-only ISO 8601 strings start with
        # T, but the extended format allows this to be omitted as long as there
        # is no ambiguity with date strings.
        time_string = time_string.removeprefix('T')

        try:
            time_components, _, error_from_components, error_from_tz = (
                _parse_isoformat_time(time_string)
            )
        except ValueError:
            raise ValueError(
                f'Invalid isoformat string: {time_string!r}') from None
        else:
            if error_from_tz:
                raise error_from_tz
            if error_from_components:
                raise ValueError(
                    "Minute, second, and microsecond must be 0 when hour is 24"
                )

            return cls(*time_components)

    def strftime(self, format):
        """Format using strftime().  The date part of the timestamp passed
        to underlying strftime should not be used.

        For a list of supported format codes, see the documentation:
            https://docs.python.org/3/library/datetime.html#format-codes
        """
        # The year must be >= 1000 else Python's strftime implementation
        # can raise a bogus exception.
        timetuple = (1900, 1, 1,
                     self._hour, self._minute, self._second,
                     0, 1, -1)
        return _wrap_strftime(self, format, timetuple)

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Parse durations as timedelta, not time: convert '24:30:00' by splitting components into timedelta(hours=24, minutes=30)
  2. If the value is genuinely end-of-day, use exactly '24:00:00' or normalize to time(0,0)
  3. Validate hour<24 (or ==24 with zero remainder) before calling fromisoformat

Example fix

# before
t = time.fromisoformat('24:30:00')  # ValueError

# after
from datetime import timedelta
h, m, s = map(int, '24:30:00'.split(':'))
d = timedelta(hours=h, minutes=m, seconds=s)
Defensive patterns

Strategy: validation

Validate before calling

def parse_hour24(s: str):
    h, rest = int(s[0:2]), s[2:]
    if h == 24 and rest not in (':00:00', ':00:00.000000', ''):
        raise ValueError('hour 24 requires zero minutes/seconds/microseconds')
    return time.fromisoformat(s) if h < 24 else time(0, 0)

Type guard

def is_duration_like(s: str) -> bool:
    return int(s[0:2]) >= 24

Try / catch

try:
    t = time.fromisoformat(s)
except ValueError as e:
    if 'hour is 24' in str(e):
        h, m, sec = map(int, s.split(':'))
        t = timedelta(hours=h, minutes=m, seconds=sec)  # reinterpret as duration
    else:
        raise

Prevention

When it happens

Trigger: time.fromisoformat('24:00:01'); time.fromisoformat('24:15:00'); time.fromisoformat('24:00:00.000001'); data feeds that compute durations as hours and emit 24:xx when a task crosses midnight.

Common situations: Duration-like 'HH:MM:SS' strings fed to a time parser — 25+ hours or 24:30 from overnight shifts, media timestamps, or elapsed-time reports; duration fields mis-modeled as clock times.

Related errors


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