From d65ec4f22f91eab2d8e3e03e15f8e95b45150e0a Mon Sep 17 00:00:00 2001 From: bensynapse <118375461+bensynapse@users.noreply.github.com> Date: Fri, 2 Oct 2026 11:45:50 +0300 Subject: [PATCH] Fix nth weekday matches on day 31 --- packages/matcher/src/matcher.ts | 7 +--- packages/matcher/test/unit/matcher.spec.ts | 41 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/packages/matcher/src/matcher.ts b/packages/matcher/src/matcher.ts index 097f126..40a4fe5 100644 --- a/packages/matcher/src/matcher.ts +++ b/packages/matcher/src/matcher.ts @@ -338,13 +338,8 @@ function getLastWeekDay(time: DateTime) { */ function getDaysOfType(time: DateTime, day: number) { const days: number[] = []; - for (let i = 1; i < 31; i++) { + for (let i = 1; i <= time.daysInMonth; i++) { const newTime = time.set({day: i}); - if (newTime.month != time.month) { - // means it split over to next month - break; - } - if (getWeekDay(newTime) === day) { days.push(newTime.day); } diff --git a/packages/matcher/test/unit/matcher.spec.ts b/packages/matcher/test/unit/matcher.spec.ts index 8290fda..3b7cd61 100644 --- a/packages/matcher/test/unit/matcher.spec.ts +++ b/packages/matcher/test/unit/matcher.spec.ts @@ -604,6 +604,47 @@ describe('getFutureMatches', () => { }); }); +describe('nth weekday on day 31', () => { + const cases = [ + ['sun', '2020-05-31', '2020-06-01'], + ['mon', '2020-08-31', '2020-09-01'], + ['tue', '2020-03-31', '2020-04-01'], + ['wed', '2021-03-31', '2021-04-01'], + ['thu', '2020-12-31', '2021-01-01'], + ['fri', '2020-07-31', '2020-08-01'], + ['sat', '2020-10-31', '2020-11-01'], + ]; + + it.each(cases)('matches the fifth %s on %s', (weekday, date) => { + expect(subject.isTimeMatches(`0 0 ? * ${weekday}#5`, `${date}T00:00:00Z`)).toBe(true); + expect(subject.isTimeMatches(`0 0 ? * ${weekday}#4`, `${date}T00:00:00Z`)).toBe(false); + }); + + it.each(cases)('returns the fifth %s on %s', (weekday, date, endDate) => { + expectFutureMatches(`0 0 ? * ${weekday}#5`, [`${date}T00:00:00Z`], { + startAt: `${date}T00:00:00Z`, + endAt: `${endDate}T00:00:00Z`, + }); + }); + + it('returns all fifth Fridays within the year', () => { + expectFutureMatches( + '0 0 ? * fri#5', + ['2020-01-31T00:00:00Z', '2020-05-29T00:00:00Z', '2020-07-31T00:00:00Z', '2020-10-30T00:00:00Z'], + {endAt: '2021-01-01T00:00:00Z'} + ); + }); + + it('skips a month without a fifth Friday', () => { + expect( + subject.getFutureMatches('0 0 ? * fri#5', { + startAt: '2021-02-01T00:00:00Z', + endAt: '2021-03-01T00:00:00Z', + }) + ).toEqual([]); + }); +}); + describe('getFutureMatches with timezones', () => { it('1 am every day in pacific', () => { expectFutureMatches('0 1 * *', ['2020-01-01T09:00:00Z', '2020-01-02T09:00:00Z'], {timezone: 'America/Los_Angeles'});