fix(schedule): keep low-year LMT handoff safe
This commit is contained in:
@@ -815,12 +815,15 @@ function ownedLowYearCronInstant(
|
||||
function nextCronInstant(rule: ParsedCronRule, timeZone: string, after: number): number | undefined {
|
||||
if (!rule.hasMatchingDate) return undefined
|
||||
let cursor = after
|
||||
const formatter = cronLocalFormatter(timeZone)
|
||||
if (new Date(after).getUTCFullYear() <= CRONER_LOW_YEAR_CUTOFF) {
|
||||
const lower = ownedLowYearCronInstant(rule, timeZone, after, 1)
|
||||
if (lower !== undefined) return lower
|
||||
if (localProjection(formatter, after).offset % 60_000 !== 0) {
|
||||
cursor = cursorBeforeNextOffsetTransition(formatter, after)
|
||||
}
|
||||
}
|
||||
const evaluator = cronEvaluator(rule, timeZone)
|
||||
const formatter = cronLocalFormatter(timeZone)
|
||||
let gapCorrections = 0
|
||||
while (cursor < MAX_FOUR_DIGIT_YEAR_MS) {
|
||||
const candidate = evaluator.nextRun(new Date(cursor))
|
||||
@@ -840,6 +843,7 @@ function nextCronInstant(rule: ParsedCronRule, timeZone: string, after: number):
|
||||
}
|
||||
gapCorrections = 0
|
||||
if (epoch > MAX_FOUR_DIGIT_YEAR_MS) return undefined
|
||||
/* v8 ignore next 3 -- current IANA data leaves sub-minute LMT at its first transition. */
|
||||
if (epoch % 60_000 !== 0) {
|
||||
cursor = cursorBeforeNextOffsetTransition(formatter, epoch)
|
||||
continue
|
||||
|
||||
@@ -246,15 +246,23 @@ describe('Croner calendar adapter', () => {
|
||||
})
|
||||
|
||||
it('skips a sub-minute local-mean-time era before iterating dense safe-year matches', () => {
|
||||
const record = createCronScheduleRecord(
|
||||
const yearOne = createCronScheduleRecord(
|
||||
ScheduleId('schedule-sub-minute-offset-year-one'),
|
||||
'standard-time handoff',
|
||||
'*/5 * * * *',
|
||||
'Europe/Amsterdam',
|
||||
Date.parse('0001-01-01T00:00:00.000Z'),
|
||||
)
|
||||
const yearOneHundred = createCronScheduleRecord(
|
||||
ScheduleId('schedule-sub-minute-offset'),
|
||||
'standard-time handoff',
|
||||
'*/5 * * * *',
|
||||
'Europe/Amsterdam',
|
||||
Date.parse('0100-01-01T00:00:00.000Z'),
|
||||
)
|
||||
expect(new Date(record.scheduledAt).getUTCFullYear()).toBeGreaterThan(109)
|
||||
expect(Math.abs(Date.parse(record.scheduledAt) % 60_000)).toBe(0)
|
||||
expect(yearOne.scheduledAt).toBe(yearOneHundred.scheduledAt)
|
||||
expect(new Date(yearOne.scheduledAt).getUTCFullYear()).toBeGreaterThan(109)
|
||||
expect(Math.abs(Date.parse(yearOne.scheduledAt) % 60_000)).toBe(0)
|
||||
}, 1_000)
|
||||
|
||||
it('selects the latest current match after a persisted baseline', () => {
|
||||
|
||||
Reference in New Issue
Block a user