Repository navigation
Reject %z offsets of 24 hours or more in strptime - #32
Conversation
%z hours are now held to 00-23, as its minutes already are to 00-59, so +2400, -2400 and +9959 fail with the same "%z out of range" error that +0960 gets. RFC 3339 caps time-hour at 23, and Python's strptime refuses any offset of 24 hours or more.
There was a problem hiding this comment.
Build & Tests
- CI: green on ubuntu-latest and macos-latest. That covers the
-Werrortest run, angler,carp-fmt --checkand gendocs. - Local: I checked out
ec61dadand ran CI's-Werrorwrapper, with(add-cflag "-Werror")before(load "test/time.carp"). It builds cleanly and passes 378/0.
Findings
No bugs found. The change is one condition at time.carp:1085. hhmm comes from parse-digits with n = 4, which only accepts ASCII digits, so it is always in 0..9999. (/ hhmm 100) is therefore the hour field, 0..99, and > 23 rejects exactly 24–99. The error message still slices the sign plus four digits, so it reads %z out of range: +2400, matching #31's minutes message.
The tests catch it. Each row below is a git archive copy of the head, run under the same -Werror wrapper:
| variant | result | failing tests |
|---|---|---|
| head | 378/0 | none |
| fix reverted (minutes-only check) | 375/3 | the three new rejection tests (+2400, -2400, +9959) |
> 24 instead of > 23 |
376/2 | +2400 and -2400 |
>= 23 instead of > 23 |
376/2 | +2359 and -2359 accepted |
or changed to and |
373/5 | the three new tests plus #31's +0560 and +0999 tests |
So the reverted run fails exactly as the PR body says, and both boundaries are pinned on each side.
Oracle. Python 3.11 datetime.strptime(x, "%z") gives the same split on all six of the PR's inputs. It rejects +2400, -2400 and +9959, and accepts +2359, -2359 and +0000 as ±86340 and 0 seconds. It also agrees on -0000 (0), +1400 and -1200.
Informational, no action needed: glibc's strptime (2.36) and Python's time.strptime still accept offsets up to +9959 (86400, -86400 and 359940 seconds for the three rejected inputs). Both bound only the minutes. Datetime.strptime returns a Datetime with a Timezone, so datetime.strptime and RFC 3339's time-hour are the right model, and the doc line at time.carp:787 now states the range. strptime is the only offset parser in time.carp, so the same bug exists nowhere else in the file.
No CHANGELOG exists in this repo, and none is needed.
Verdict: merge
It is a correct, minimal one-condition bound with the doc line updated, and both boundaries are pinned by tests that fail without the fix. Builds under -Werror, 378/0, CI green on both platforms.
strptime's%znow refuses an offset whose hour is 24 or more.+2400,-2400and+9959fail with the existing%z out of range: …error, as+0960already does. #31 bounded only the minutes. RFC 3339 definestime-houras 00–23, and Python'sdatetime.strptimeraisesValueErrorfor any offset of 24 hours or more. The%zline of the doc string now states the hour range too.New tests:
+2400,-2400and+9959are rejected with the out-of-range message.+2359,-2359and+0000still parse, to 86340, -86340 and 0 seconds. Python 3.11 splits all six the same way. With the fix reverted, exactly the three rejection tests fail (they parse to 86400, -86400 and 359940 seconds). With it, the suite passes 378/0 under CI's-Werrorwrapper.carp-fmt -candanglerare clean on both files.Opened by the carpentry-org heartbeat agent (Claude). Veit has not reviewed this yet.