From 8766b7c6b32aedf37d7f8f350e461931b253a4fb Mon Sep 17 00:00:00 2001 From: Hivert Quentin Date: Tue, 17 Jun 2025 11:31:00 +0200 Subject: [PATCH] fix(calendar): properly evalute last occurance freebusy --- SOPE/NGCards/iCalDailyRecurrenceCalculator.m | 23 +++++++++++-------- .../NGCards/iCalMonthlyRecurrenceCalculator.m | 23 +++++++++++-------- SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m | 23 +++++++++++-------- SOPE/NGCards/iCalYearlyRecurrenceCalculator.m | 23 +++++++++++-------- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m index 817f4629e..7ecc8f09c 100644 --- a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m @@ -55,7 +55,7 @@ - (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r { NSMutableArray *ranges; - NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate; + NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate; iCalByDayMask *dayMask; long i, count, repeatCount; unsigned interval; @@ -63,6 +63,7 @@ //[self logWithFormat: @"Recurrence rule is %@", rrule]; firStart = [firstRange startDate]; + firEnd = [firstRange endDate]; startDate = [_r startDate]; endDate = [_r endDate]; dayMask = nil; @@ -84,13 +85,14 @@ // If rule is bound, check the bounds if (![rrule isInfinite]) { - NSCalendarDate *until, *lastDate; + NSCalendarDate *until, *lastStartDate, *lastEndDate; - lastDate = nil; + lastStartDate = nil; + lastEndDate = nil; until = [rrule untilDate]; if (until) { - lastDate = until; + lastStartDate = until; } else { @@ -98,20 +100,23 @@ if (dayMask == nil) // If there's no day mask, we can compute the date of the last // occurrence of the recurrent rule. - lastDate = [firStart dateByAddingYears: 0 months: 0 + lastStartDate = [firStart dateByAddingYears: 0 months: 0 + days: (interval + * (repeatCount - 1))]; + lastEndDate = [firEnd dateByAddingYears: 0 months: 0 days: (interval * (repeatCount - 1))]; } - if (lastDate != nil) + if (lastStartDate != nil && lastEndDate != nil) { - if ([lastDate compare: startDate] == NSOrderedAscending) + if ([lastEndDate compare: startDate] == NSOrderedAscending) // Range starts after last occurrence return nil; - if ([lastDate compare: endDate] == NSOrderedAscending) + if ([lastStartDate compare: endDate] == NSOrderedAscending) // Range ends after last occurence; adjust end date - endDate = lastDate; + endDate = lastStartDate; } } diff --git a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m index 6cd6814ba..5879ed252 100644 --- a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m @@ -185,7 +185,7 @@ static inline unsigned iCalDoWForNSDoW (int dow) // TODO: check whether this is OK for multiday-events! NSMutableArray *ranges; NSTimeZone *timeZone; - NSCalendarDate *eventStartDate, *rStart, *rEnd, *until, *referenceDate; + NSCalendarDate *eventStartDate, *eventEndDate, *rStart, *rEnd, *untilStart, *untilEnd, *referenceDate; int eventDayOfMonth; unsigned monthIdxInRange, numberOfMonthsInRange, interval, repeatCount; int diff, count; @@ -199,12 +199,14 @@ static inline unsigned iCalDoWForNSDoW (int dow) iCalByDayMask *byDayMask; eventStartDate = [firstRange startDate]; + eventEndDate = [firstRange endDate]; eventDayOfMonth = [eventStartDate dayOfMonth]; timeZone = [eventStartDate timeZone]; rStart = [_r startDate]; rEnd = [_r endDate]; interval = [rrule repeatInterval]; - until = nil; + untilStart = nil; + untilEnd = nil; repeatCount = [rrule repeatCount]; byMonth = [rrule byMonth]; byMonthDay = [rrule byMonthDay]; @@ -218,24 +220,27 @@ static inline unsigned iCalDoWForNSDoW (int dow) { // When there's no BYxxx mask, we can find the date of the last // occurrence. - until = [eventStartDate dateByAddingYears: 0 + untilStart = [eventStartDate dateByAddingYears: 0 months: (interval * (repeatCount - 1)) days: 0]; + untilEnd = [eventEndDate dateByAddingYears: 0 + months: (interval * (repeatCount - 1)) + days: 0]; } else { - until = [rrule untilDate]; + untilStart = [rrule untilDate]; } } - if (until != nil) + if (untilStart != nil) { - if ([until compare: rStart] == NSOrderedAscending) + if ([untilEnd compare: rStart] == NSOrderedAscending) // Range starts after last occurrence return nil; - if ([until compare: rEnd] == NSOrderedAscending) + if ([untilStart compare: rEnd] == NSOrderedAscending) // Range ends after last occurence; adjust end date - rEnd = until; + rEnd = untilStart; } if (byMonth && [byMonth count] > 0) @@ -441,7 +446,7 @@ static inline unsigned iCalDoWForNSDoW (int dow) start = [cursor dateByAddingYears: 0 months: 0 days: (dom - 1)]; doCont = [self _addInstanceWithStartDate: start - limitDate: until + limitDate: untilStart limitRange: _r toArray: ranges]; //NSLog(@"*** MONTHLY [%i/%i] adding %@%@ (count = %i)", dom, numDaysInMonth, start, (doCont?@"":@" .. NOT!"), count); diff --git a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m index e3786ba7a..5be2a1344 100644 --- a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m @@ -64,7 +64,7 @@ - (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r { NSMutableArray *ranges; - NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate; + NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate; long i, repeatCount, count; unsigned interval; iCalByDayMask *dayMask; @@ -73,6 +73,7 @@ //[self logWithFormat: @"Recurrence rule is %@", rrule]; firStart = [firstRange startDate]; + firEnd = [firstRange endDate]; startDate = [_r startDate]; endDate = [_r endDate]; dayMask = nil; @@ -95,31 +96,35 @@ // If rule is bound, check the bounds if (![rrule isInfinite]) { - NSCalendarDate *until, *lastDate; + NSCalendarDate *until, *lastStartDate, *lastEndDate; - lastDate = nil; + lastStartDate = nil; + lastEndDate = nil; until = [rrule untilDate]; if (until) - lastDate = until; + lastStartDate = until; else { repeatCount = [rrule repeatCount]; if (dayMask == nil) // When there's no BYxxx mask, we can find the date of the last // occurrence. - lastDate = [firStart dateByAddingYears: 0 months: 0 + lastStartDate = [firStart dateByAddingYears: 0 months: 0 + days: (interval + * (repeatCount - 1) * 7)]; + lastEndDate = [firEnd dateByAddingYears: 0 months: 0 days: (interval * (repeatCount - 1) * 7)]; } - if (lastDate != nil) + if (lastStartDate != nil && lastEndDate != nil) { - if ([lastDate compare: startDate] == NSOrderedAscending) + if ([lastEndDate compare: startDate] == NSOrderedAscending) // Range starts after last occurrence return nil; - if ([lastDate compare: endDate] == NSOrderedAscending) + if ([lastStartDate compare: endDate] == NSOrderedAscending) // Range ends after last occurence; adjust end date - endDate = [lastDate addTimeInterval: [firstRange duration]]; + endDate = [lastStartDate addTimeInterval: [firstRange duration]]; } } diff --git a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m index 5e4fadc6f..bdf285dc7 100644 --- a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m +++ b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m @@ -44,13 +44,14 @@ { NSMutableArray *ranges; NSArray *byMonth; - NSCalendarDate *firStart, *lastDate, *rStart, *rEnd, *until, *referenceDate, *rTemp; + NSCalendarDate *firStart, *firEnd, *lastStartDate, *lastEndDate, *rStart, *rEnd, *until, *referenceDate, *rTemp; NSInteger *hoursOfOffset; iCalMonthlyRecurrenceCalculator *monthlyCalc; unsigned j, yearIdxInRange, numberOfYearsInRange, count, interval, monthDiff; int diff, repeatCount, currentMonth, origNbDaysInMonth; firStart = [firstRange startDate]; + firEnd = [firstRange endDate]; rStart = [_r startDate]; rEnd = [_r endDate]; interval = [rrule repeatInterval]; @@ -71,33 +72,37 @@ // If rule is bound, check the bounds if (![rrule isInfinite]) { - lastDate = nil; + lastStartDate = nil; + lastEndDate = nil; until = [rrule untilDate]; repeatCount = [rrule repeatCount]; if (until) { - lastDate = until; + lastStartDate = until; } if (repeatCount > 0) { - if (lastDate == nil && ![rrule hasByMask]) + if (lastStartDate == nil && ![rrule hasByMask]) // When there's no BYxxx mask, we can find the date of the last // occurrence. - lastDate = [firStart dateByAddingYears: (interval * (repeatCount - 1)) + lastStartDate = [firStart dateByAddingYears: (interval * (repeatCount - 1)) + months: 0 + days: 0]; + lastEndDate = [firEnd dateByAddingYears: (interval * (repeatCount - 1)) months: 0 days: 0]; referenceDate = firStart; } - if (lastDate != nil) + if (lastStartDate != nil) { - if ([lastDate compare: rStart] == NSOrderedAscending) + if ([lastEndDate compare: rStart] == NSOrderedAscending) // Range starts after last occurrence return nil; - if ([lastDate compare: rEnd] == NSOrderedAscending) + if ([lastStartDate compare: rEnd] == NSOrderedAscending) // Range ends after last occurence; adjust end date - rEnd = [lastDate addTimeInterval: [firstRange duration]]; + rEnd = [lastStartDate addTimeInterval: [firstRange duration]]; } }