hour(n) with n >= 24 clamped n to 24, which walkTo() rejects as an invalid hour (valid range 0-23), nulling the epoch and invalidating the object. Clamp to 23 to match the other overflow-clamping setters (date, month).
2.0 KiB
Fix hour() setter clamping to an invalid hour (24)
Problem
Calling .hour(n) with n >= 24 produces an invalid spacetime whose epoch is
null, instead of clamping to a valid hour:
const s = spacetime('2021-03-14 10:00:00', 'UTC')
s.hour(24).isValid() // false
s.hour(24).epoch // null
s.hour(25).format('iso') // '' (empty - object is invalid)
This is inconsistent with every other overflow-clamping setter:
.date(40)clamps to the last day of the month,.month(13)clamps to December (11),.hour(-1)clamps to 0.
Only the upper bound of .hour() is broken.
Root cause
src/methods/set/set.js, in hours():
if (n >= 24) {
n = 24
} else if (n < 0) {
n = 0
}
Valid hours are 0-23. Clamping to 24 yields a value that
src/methods/set/walk.js rejects (hour.valid: (n) => n >= 0 && n < 24), and
on an invalid unit walkTo() sets s.epoch = null, invalidating the whole
object. The negative branch is already correct (clamps to the valid 0); the
>= 24 branch is off by one and should clamp to 23.
Fix
if (n >= 24) {
n = 23
} else if (n < 0) {
n = 0
}
hour(24), hour(25), hour(100) now all clamp to 23:00 on the same day,
matching the behavior of the other setters.
Test
Added a test to test/set.test.js (next to the existing month/date clamp test)
asserting that out-of-range hours clamp to 23, keep the object valid, keep the
same day, and that negatives still clamp to 0.
Counterfactual (revert n = 23 back to n = 24):
not ok - hour(24) clamps to 23
operator: equal
expected: 23
actual: 0
(the invalid object reports hour 0).
Gate
npm test(tape) run againstsrc(the default dev target oftest/lib/index.js): the new test passes; the full suite shows only 18 pre-existing DST/timezone failures (europe/london,atlantic/madeira,atlantic/azores, some date-dependent "dst-now") that are present verbatim without this change and are unrelated to it.npm run lint(eslint ./src): exit 0.