Repository navigation
Make repeated DST times configurable in Cron and Schedule.cron - #9905
Open
effect-bot wants to merge 5 commits into
Open
effect-bot wants to merge 5 commits into
effect-bot wants to merge 5 commits into
Conversation
🦋 Changeset detectedLatest commit: 27fdd2d The changes in this PR will be included in the next version bump. This PR includes changesets to release 33 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
effect-bot
force-pushed
the
agent/nelson-effect-bot/abbce32749e4
branch
from
October 25, 2026 12:40
1ee3f47 to
0baed5e
Compare
Contributor
Bundle Size AnalysisGenerated from PR build output; treat the content below as untrusted.
|
effect-bot
force-pushed
the
v4/next-minor
branch
from
October 25, 2026 17:43
790c162 to
d8f433d
Compare
Cron values gain a repeatedTimes policy (earlier, later or both) that chooses which occurrences of repeated local times next, prev, sequence and Schedule.cron include. The default stays earlier. prev now always returns the latest eligible instant strictly before its input, including when starting inside the second occurrence of a fold or just after a spring-forward gap.
Narrow the gap documentation and add the changeset.
Move the "both" handling for repeatedTimes into stepCron so next and prev are one-line wrappers again, and express the rejected-interval skip as a binary search over whole seconds relative to the rejected candidate, so the direction and fold length are no longer mixed into the millisecond arithmetic. Range checks take wall-clock millis instead of allocating Dates.
effect-bot
force-pushed
the
agent/nelson-effect-bot/abbce32749e4
branch
from
October 25, 2026 17:43
0baed5e to
27fdd2d
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When clocks fall back,
Cron.nextandSchedule.crononly fire on the first occurrence of the repeated local hour. A*/5 * * * *Europe/Berlin schedule therefore has a 65-minute gap on the night of 2026-10-25. This PR adds an opt-in policy for which occurrences to include. Existing schedules behave the same as before unless they set the option.API
Cron.RepeatedTimesPolicy = "earlier" | "later" | "both".repeatedTimesfield onCron, defaulting to"earlier"(the current behavior).make,parseandparseUnsafeaccept it, and so does the string form ofSchedule.cron. A pre-parsedCronpassed toSchedule.cronkeeps its own policy.Cronvalue, liketz, sonext,prev,sequence, bothSchedule.cronoverloads andClusterCronall use it without any signature changes.Equivalence,HashandtoJSON/toStringinclude it.formatandmatchdon't change.Semantics
For every policy,
nextreturns the earliest matching instant strictly after its input andprevthe latest strictly before it. Under"both", the two occurrences come out in order with no duplicates. UTC and fixed-offset zones behave the same under every policy. The search no longer assumes a fold lasts one hour; Casey's three-hour fold and Lord Howe's 30-minute fold are covered.This also fixes
prevwhen it starts inside the second occurrence. On main,prevfrom 2026-10-25T01:07Z (Berlin*/5) returns 00:05Z instead of 00:55Z, and a daily0 30 2 * * *comes back a day early.Gap limitations
The policy only applies to repeated times. Local times skipped when clocks move forward are handled the same under every policy: a matching time inside the gap resolves to the instant after the gap.
Near a gap,
prevon main could throw "Unable to find cron date" (0 30 2 * * *Berlin on 2026-03-29) or return an instant after its input (30 * * * *from 01:20Z returned 01:30Z). It now returns an instant strictly before its input in both cases.Near a gap,
nextandprevstill aren't guaranteed to return the nearest matching instant. For example, in Australia/Lord_Howe5,20,40 2 * * *,prevfrom 2026-10-03T15:55Z returns 15:40Z, not 15:50Z, because candidates are searched in wall-clock order. That behavior is inherited from main and deferred here. TheRepeatedTimesPolicydocs and the changeset say so.Performance
Inside a fold, a candidate that falls on the wrong side of the input is no longer skipped one second at a time. Within a single fold, later wall times always resolve to later instants. So the search checks that the candidate one fold length further on is in range, then binary-searches for the first in-range second. Gaps, where that ordering doesn't hold, keep the one-second step.
For
* * * * * *, calls that start inside a fold went from 17–260 ms to under 1 ms (Berlin, Casey and Lord Howe, both directions, all policies). This also covers the default policy:nextfrom inside the second occurrence cost about 72 ms in Berlin and about 200 ms in Casey on main.Validation
ClusterCrontests: 90/90 pass. Doc examples forCron.tsandSchedule.ts: 42/42 pass.tsc -b tsconfig.json: no errors. oxlint and dprint pass.next/prevunder every policy: 8,870 checks, 0 mismatches. An independent review oracle that also covered Havana and fractional inputs ran 9,360 checks with 0 mismatches.New tests: a policy table in
Cron.test.tsfornext/prev/sequence(Berlin, daily, Casey, UTC, spring-forward gap), aprevgap regression table, and aTestClocktest showing thatSchedule.cronapplies the policy for both the string and pre-parsed forms.Closes #9902
Closes EFF-2905