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

ISO 8601 allows the special value hour=24 only to mean midnight of the next day. fromisoformat's time parser returns an error_from_components flag when hour is 24 but minute, second, or microsecond is nonzero, and the datetime constructor path raises this explicit ValueError instead of the generic invalid-isoformat message.

Source

Thrown at Lib/_pydatetime.py:1986

            date_components = _parse_isoformat_date(dstr)
        except ValueError:
            raise ValueError(
                f'Invalid isoformat string: {date_string!r}') from None

        if tstr:
            try:
                (time_components,
                 became_next_day,
                 error_from_components,
                 error_from_tz) = _parse_isoformat_time(tstr)
            except ValueError:
                raise ValueError(
                    f'Invalid isoformat string: {date_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")

                if became_next_day:
                    year, month, day = date_components
                    # Only wrap day/month when it was previously valid
                    if 1 <= month <= 12 and day <= (days_in_month := _days_in_month(year, month)):
                        # Calculate midnight of the next day
                        day += 1
                        if day > days_in_month:
                            day = 1
                            month += 1
                            if month > 12:
                                month = 1
                                year += 1
                        date_components = [year, month, day]
        else:
            time_components = [0, 0, 0, 0, None]

        return cls(*(date_components + time_components))

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Normalize the source data: convert hour 24 with remainder into a next-day datetime with hour 0..23 plus timedelta
  2. Use timedelta arithmetic on datetimes instead of string hour math
  3. Pre-validate: if the time part starts with '24' and has nonzero lower components, rewrite before parsing

Example fix

// before
dt = datetime.fromisoformat('2024-01-01T24:30:00')  # raises

# after
dt = datetime.fromisoformat('2024-01-01T00:00:00') + timedelta(days=1, minutes=30)
Defensive patterns

Strategy: validation

Validate before calling

import re
HOUR24 = re.compile(r'T24:(?!00(:00(.0*)?)?$)')
if HOUR24.search(ts):
    # hour 24 with nonzero components: normalize manually
    dt = datetime.fromisoformat(ts.replace('T24', 'T00')) + timedelta(days=1)
else:
    dt = datetime.fromisoformat(ts)

Try / catch

try:
    dt = datetime.fromisoformat(ts)
except ValueError as e:
    if 'hour is 24' in str(e):
        dt = datetime.fromisoformat(ts[:ts.index('T')] + 'T00:00:00') + timedelta(days=1)
    else:
        raise

Prevention

When it happens

Trigger: Strings like '2024-01-01T24:15:00' or '2024-01-01T24:00:00.000001'. Only exactly 'T24:00[:00[.000...]]' is accepted (yielding next-day midnight).

Common situations: Data feeds that normalize end-of-day as 24:00 plus a duration; scheduling systems encoding 'until midnight' as 24:xx; naive string arithmetic on hours that rolls 23:30 + 60min into '24:30'.

Related errors


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