@@ -467,6 +467,7 @@ def _parse_isoformat_time(tstr):
467467    hour , minute , second , microsecond  =  time_comps 
468468    became_next_day  =  False 
469469    error_from_components  =  False 
470+     error_from_tz  =  None 
470471    if  (hour  ==  24 ):
471472        if  all (time_comp  ==  0  for  time_comp  in  time_comps [1 :]):
472473            hour  =  0 
@@ -500,14 +501,22 @@ def _parse_isoformat_time(tstr):
500501        else :
501502            tzsign  =  - 1  if  tstr [tz_pos  -  1 ] ==  '-'  else  1 
502503
503-             td  =  timedelta (hours = tz_comps [0 ], minutes = tz_comps [1 ],
504-                            seconds = tz_comps [2 ], microseconds = tz_comps [3 ])
505- 
506-             tzi  =  timezone (tzsign  *  td )
504+             try :
505+                 # This function is intended to validate datetimes, but because 
506+                 # we restrict time zones to ±24h, it serves here as well. 
507+                 _check_time_fields (hour = tz_comps [0 ], minute = tz_comps [1 ],
508+                                    second = tz_comps [2 ], microsecond = tz_comps [3 ],
509+                                    fold = 0 )
510+             except  ValueError  as  e :
511+                 error_from_tz  =  e 
512+             else :
513+                 td  =  timedelta (hours = tz_comps [0 ], minutes = tz_comps [1 ],
514+                                seconds = tz_comps [2 ], microseconds = tz_comps [3 ])
515+                 tzi  =  timezone (tzsign  *  td )
507516
508517    time_comps .append (tzi )
509518
510-     return  time_comps , became_next_day , error_from_components 
519+     return  time_comps , became_next_day , error_from_components ,  error_from_tz 
511520
512521# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar 
513522def  _isoweek_to_gregorian (year , week , day ):
@@ -1633,9 +1642,21 @@ def fromisoformat(cls, time_string):
16331642        time_string  =  time_string .removeprefix ('T' )
16341643
16351644        try :
1636-             return  cls (* _parse_isoformat_time (time_string )[0 ])
1637-         except  Exception :
1638-             raise  ValueError (f'Invalid isoformat string: { time_string !r}  )
1645+             time_components , _ , error_from_components , error_from_tz  =  (
1646+                 _parse_isoformat_time (time_string )
1647+             )
1648+         except  ValueError :
1649+             raise  ValueError (
1650+                 f'Invalid isoformat string: { time_string !r}  ) from  None 
1651+         else :
1652+             if  error_from_tz :
1653+                 raise  error_from_tz 
1654+             if  error_from_components :
1655+                 raise  ValueError (
1656+                     "Minute, second, and microsecond must be 0 when hour is 24" 
1657+                 )
1658+ 
1659+             return  cls (* time_components )
16391660
16401661    def  strftime (self , format ):
16411662        """Format using strftime().  The date part of the timestamp passed 
@@ -1947,11 +1968,16 @@ def fromisoformat(cls, date_string):
19471968
19481969        if  tstr :
19491970            try :
1950-                 time_components , became_next_day , error_from_components  =  _parse_isoformat_time (tstr )
1971+                 (time_components ,
1972+                  became_next_day ,
1973+                  error_from_components ,
1974+                  error_from_tz ) =  _parse_isoformat_time (tstr )
19511975            except  ValueError :
19521976                raise  ValueError (
19531977                    f'Invalid isoformat string: { date_string !r}  ) from  None 
19541978            else :
1979+                 if  error_from_tz :
1980+                     raise  error_from_tz 
19551981                if  error_from_components :
19561982                    raise  ValueError ("minute, second, and microsecond must be 0 when hour is 24" )
19571983
0 commit comments