{"record":{"id":"1ae9dadf19ea6664","repo":"python/cpython","slug":"minute-second-and-microsecond-must-be-0-when-hou-1ae9da","errorCode":null,"errorMessage":"minute, second, and microsecond must be 0 when hour is 24","messagePattern":"minute, second, and microsecond must be 0 when hour is 24","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":1986,"sourceCode":"            date_components = _parse_isoformat_date(dstr)\n        except ValueError:\n            raise ValueError(\n                f'Invalid isoformat string: {date_string!r}') from None\n\n        if tstr:\n            try:\n                (time_components,\n                 became_next_day,\n                 error_from_components,\n                 error_from_tz) = _parse_isoformat_time(tstr)\n            except ValueError:\n                raise ValueError(\n                    f'Invalid isoformat string: {date_string!r}') from None\n            else:\n                if error_from_tz:\n                    raise error_from_tz\n                if error_from_components:\n                    raise ValueError(\"minute, second, and microsecond must be 0 when hour is 24\")\n\n                if became_next_day:\n                    year, month, day = date_components\n                    # Only wrap day/month when it was previously valid\n                    if 1 <= month <= 12 and day <= (days_in_month := _days_in_month(year, month)):\n                        # Calculate midnight of the next day\n                        day += 1\n                        if day > days_in_month:\n                            day = 1\n                            month += 1\n                            if month > 12:\n                                month = 1\n                                year += 1\n                        date_components = [year, month, day]\n        else:\n            time_components = [0, 0, 0, 0, None]\n\n        return cls(*(date_components + time_components))","sourceCodeStart":1968,"sourceCodeEnd":2004,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pydatetime.py#L1968-L2004","documentation":"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.","triggerScenarios":"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).","commonSituations":"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'.","solutions":["Normalize the source data: convert hour 24 with remainder into a next-day datetime with hour 0..23 plus timedelta","Use timedelta arithmetic on datetimes instead of string hour math","Pre-validate: if the time part starts with '24' and has nonzero lower components, rewrite before parsing"],"exampleFix":"// before\ndt = datetime.fromisoformat('2024-01-01T24:30:00')  # raises\n\n# after\ndt = datetime.fromisoformat('2024-01-01T00:00:00') + timedelta(days=1, minutes=30)","handlingStrategy":"validation","validationCode":"import re\nHOUR24 = re.compile(r'T24:(?!00(:00(.0*)?)?$)')\nif HOUR24.search(ts):\n    # hour 24 with nonzero components: normalize manually\n    dt = datetime.fromisoformat(ts.replace('T24', 'T00')) + timedelta(days=1)\nelse:\n    dt = datetime.fromisoformat(ts)","typeGuard":null,"tryCatchPattern":"try:\n    dt = datetime.fromisoformat(ts)\nexcept ValueError as e:\n    if 'hour is 24' in str(e):\n        dt = datetime.fromisoformat(ts[:ts.index('T')] + 'T00:00:00') + timedelta(days=1)\n    else:\n        raise","preventionTips":["Represent end-of-day as next-day midnight with hour 0","Use timedelta arithmetic instead of hour-24 strings","Reject hour 24 in input validation except exact 'T24:00'"],"tags":["python","datetime","value-error","iso8601","parsing"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}