From 2798f4bdcb3a3ace830e590a0dac2120a72e67f2 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Mon, 25 Aug 2025 20:39:44 -0600 Subject: [PATCH] Fix event repetition counting on events that don't initiate on their repeat days. --- src/utils/date.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/utils/date.js b/src/utils/date.js index 523a3a1..d6e5f7b 100644 --- a/src/utils/date.js +++ b/src/utils/date.js @@ -100,9 +100,13 @@ function getWeeklyOccurrenceIndex(event, dateStr, timeZone = DEFAULT_TZ) { const weekDiff = dateFns.differenceInCalendarWeeks(currentBlockStart, baseBlockStart) if (weekDiff < 0 || weekDiff % interval !== 0) return null + const baseDow = dateFns.getDay(baseStart) + const baseCountsAsPattern = !!pattern[baseDow] + // Same ISO week as base: count pattern days from baseStart up to target (inclusive) if (weekDiff === 0) { - const n = countPatternDaysInInterval(baseStart, target, pattern) - 1 + let n = countPatternDaysInInterval(baseStart, target, pattern) - 1 + if (!baseCountsAsPattern) n += 1 // Shift indices so base occurrence stays 0 return n < 0 || n >= event.repeatCount ? null : n } @@ -114,7 +118,8 @@ function getWeeklyOccurrenceIndex(event, dateStr, timeZone = DEFAULT_TZ) { const middleWeeksCount = alignedWeeksBetween > 0 ? alignedWeeksBetween * fullPatternWeekCount : 0 // Count pattern days in the current (possibly partial) week from currentBlockStart..target const currentWeekCount = countPatternDaysInInterval(currentBlockStart, target, pattern) - const n = firstWeekCount + middleWeeksCount + currentWeekCount - 1 + let n = firstWeekCount + middleWeeksCount + currentWeekCount - 1 + if (!baseCountsAsPattern) n += 1 return n >= event.repeatCount ? null : n } @@ -155,6 +160,11 @@ function getWeeklyOccurrenceDate(event, occurrenceIndex, timeZone = DEFAULT_TZ) if (occurrenceIndex === 0) return toLocalString(baseStart, timeZone) const baseWeekMonday = getMondayOfISOWeek(baseStart, timeZone) const baseDow = dateFns.getDay(baseStart) + const baseCountsAsPattern = !!pattern[baseDow] + // Adjust index if base weekday is not part of the pattern (pattern occurrences shift by +1) + let occ = occurrenceIndex + if (!baseCountsAsPattern) occ -= 1 + if (occ < 0) return null // Sorted list of active weekday indices const patternDays = [] for (let d = 0; d < 7; d++) if (pattern[d]) patternDays.push(d) @@ -167,10 +177,10 @@ function getWeeklyOccurrenceDate(event, occurrenceIndex, timeZone = DEFAULT_TZ) firstWeekDates.push(date) } const F = firstWeekDates.length - if (occurrenceIndex < F) { - return toLocalString(firstWeekDates[occurrenceIndex], timeZone) + if (occ < F) { + return toLocalString(firstWeekDates[occ], timeZone) } - const remaining = occurrenceIndex - F + const remaining = occ - F const P = patternDays.length if (P === 0) return null // Determine aligned week group (k >= 1) in which the remaining-th occurrence lies