Skip to content

Commit

Permalink
Add Python implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
TizzySaurus committed Jun 17, 2023
1 parent 00ba564 commit b3890f4
Showing 1 changed file with 30 additions and 5 deletions.
35 changes: 30 additions & 5 deletions Lib/_pydatetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,16 @@ def _parse_isoformat_time(tstr):

time_comps = _parse_hh_mm_ss_ff(timestr)

hour, minute, second, microsecond = time_comps
became_next_day = False
if (hour == 24):
if not all(time_comp == 0 for time_comp in time_comps[1:]):
raise ValueError("minute, second, and microsecond must be 0 when hour is 24")

hour = 0
time_comps[0] = hour
became_next_day = True

tzi = None
if tz_pos == len_str and tstr[-1] == 'Z':
tzi = timezone.utc
Expand All @@ -456,14 +466,14 @@ def _parse_isoformat_time(tstr):
else:
tzsign = -1 if tstr[tz_pos - 1] == '-' else 1

td = timedelta(hours=tz_comps[0], minutes=tz_comps[1],
seconds=tz_comps[2], microseconds=tz_comps[3])
td = timedelta(hours=hour, minutes=minute,
seconds=second, microseconds=microsecond)

tzi = timezone(tzsign * td)

time_comps.append(tzi)

return time_comps
return time_comps, became_next_day

# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
def _isoweek_to_gregorian(year, week, day):
Expand Down Expand Up @@ -1559,7 +1569,7 @@ def fromisoformat(cls, time_string):
time_string = time_string.removeprefix('T')

try:
return cls(*_parse_isoformat_time(time_string))
return cls(*_parse_isoformat_time(time_string)[0])
except Exception:
raise ValueError(f'Invalid isoformat string: {time_string!r}')

Expand Down Expand Up @@ -1871,10 +1881,25 @@ def fromisoformat(cls, date_string):

if tstr:
try:
time_components = _parse_isoformat_time(tstr)
time_components, became_next_day = _parse_isoformat_time(tstr)
except ValueError:
raise ValueError(
f'Invalid isoformat string: {date_string!r}') from None
else:
if became_next_day:
year, month, day = date_components

# Only wrap day/month when it was previously valid
if 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]

Expand Down

0 comments on commit b3890f4

Please sign in to comment.