Skip to content

test: DST fuzzing (spec 3.6) + walker perf fix it surfaced#542

Merged
merencia merged 3 commits into
mainfrom
test/dst-fuzz
Jun 17, 2026
Merged

test: DST fuzzing (spec 3.6) + walker perf fix it surfaced#542
merencia merged 3 commits into
mainfrom
test/dst-fuzz

Conversation

@merencia

Copy link
Copy Markdown
Member

PR3 of the DST work (spec 05-spec-dst §3.6).

Fuzz tests (seeded, reproducible)

  • FZ-1: 3000 random expression × timezone × date cases — getNextMatch must always return a timestamp strictly after the reference (or fail in finite time for impossible expressions).
  • FZ-2: 10,000 chained getNextMatch across the NY DST transitions — strictly monotonic, never faster than the interval.
  • FZ-3: impossible expressions (0 0 31 2 *, etc.) fail in finite time (≤ the walk bound).
  • The RNG is seeded (FUZZ_SEED to override), so a CI failure replays exactly.

Real bug the fuzz found (and this PR fixes)

A dense-time expression also constrained by day-of-month AND weekday — e.g. * * * 15 * 1 (the 15th, only when it's a Monday) — took ~5 minutes (323,152ms) for a single getNextMatch.

Cause: the walker pre-checked month + day-of-month before the time-of-day scan, but not the weekday. On every "15th that isn't a Monday" it scanned all 86,400 hour×minute×second combinations, materializing each instant and calling match(), all rejected on weekday.

Fix: the walker now pre-checks the weekday per day (computed arithmetically — a Y/M/D's weekday is timezone-independent — mirroring exactly the conversion match() uses, so it only skips days that would be rejected anyway). * * * 15 * 1 now resolves in <1s (regression test FZ-4).

Result

314 tests green under both TZ=UTC and TZ=America/Sao_Paulo. Fuzz runs in CI (via the existing npm test).

DST plan status

merencia added 3 commits June 17, 2026 11:54
Add seeded fuzz tests (spec 3.6): 3000 random expression x timezone x date cases
that must always return a future instant, 10,000 chained getNextMatch calls that
must stay strictly monotonic across DST, and impossible expressions that must
fail in finite time. The RNG is seeded so any CI failure is reproducible.

The fuzz surfaced a real performance cliff: a dense-time expression also
constrained by day-of-month AND weekday (e.g. `* * * 15 * 1`) scanned all 86,400
times of day on every day that matched the day-of-month but not the weekday,
taking ~5 minutes for a single getNextMatch. The walker now pre-checks the
weekday (computed arithmetically, mirroring match()'s conversion) before the
time-of-day scan, skipping those days outright.
getUTCDay() and the converted weekday field share the same 0-6 (Sunday=0)
space, so the day-of-week pre-check needs no weekday-name array or
weekDayNamesConversion round-trip.
The SF-/FB-/CN-/ST-/FZ- codes and 'spec 3.x' labels meant nothing in the test
output; each test now reads as what it actually verifies.
@merencia
merencia merged commit e615fa9 into main Jun 17, 2026
6 checks passed
@merencia
merencia deleted the test/dst-fuzz branch June 17, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant