diff --git a/ChangeLog b/ChangeLog index 16748be9d..afa0d0fab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-06-04 Francis Lachapelle + + * SoObjects/Appointments/SOGoAppointmentFolder.m + (-_appendCycleException:firstInstanceCalendarDateRange:fromRow:forRange:withTimeZone:toArray:): + adjust recurrence id according to timezone when dealing with a + floating all-day event. + 2012-06-01 Francis Lachapelle * SoObjects/SOGo/NSString+Utilities.m diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.h b/SOPE/NGCards/iCalRepeatableEntityObject.h index e1f259d4e..4f7570b59 100644 --- a/SOPE/NGCards/iCalRepeatableEntityObject.h +++ b/SOPE/NGCards/iCalRepeatableEntityObject.h @@ -60,7 +60,7 @@ - (BOOL)isRecurrent; - (BOOL)isWithinCalendarDateRange:(NGCalendarDateRange *)_range - firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir; + firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir; - (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir; diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.m b/SOPE/NGCards/iCalRepeatableEntityObject.m index 5f675e29e..66173119e 100644 --- a/SOPE/NGCards/iCalRepeatableEntityObject.m +++ b/SOPE/NGCards/iCalRepeatableEntityObject.m @@ -268,6 +268,8 @@ } else { + // Example: timezone is -0400, date is 2012-05-24 (00:00:00 +0000), + // and changes to 2012-05-24 04:00:00 +0000 exDate = [dateString asCalendarDate]; offset = [(NSTimeZone *) theTimeZone secondsFromGMTForDate: exDate]; exDate = (NSCalendarDate *) [exDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 diff --git a/SOPE/NGCards/iCalTimeZone.m b/SOPE/NGCards/iCalTimeZone.m index 4754c0793..555038e5e 100644 --- a/SOPE/NGCards/iCalTimeZone.m +++ b/SOPE/NGCards/iCalTimeZone.m @@ -270,6 +270,8 @@ static NSArray *knownTimeZones; /** * Adjust a date with respect to this vTimeZone. + * Example: Timezone is -0400, the date is 2012-05-23 13:00:00 +0000: + * it returns 2012-05-23 09:00:00 +0000 * @param theDate the string representing a date. * @return a new GMT date adjusted with the offset of this timezone. */ diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 0b6f0fe37..d0b0b0969 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -744,7 +744,7 @@ static NSNumber *sharedYes = nil; { currentRecord = [recordArray objectAtIndex: count]; if ([[currentRecord objectForKey: @"startDate"] - isEqual: matchDate]) + compare: matchDate] == NSOrderedSame) recordIndex = count; else count++; @@ -773,18 +773,32 @@ static NSNumber *sharedYes = nil; firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir fromRow: (NSDictionary *) row forRange: (NGCalendarDateRange *) dateRange + withTimeZone: (NSTimeZone *) tz toArray: (NSMutableArray *) ma { NSCalendarDate *startDate, *recurrenceId; NSMutableDictionary *newRecord; NSDictionary *oldRecord; NGCalendarDateRange *newRecordRange; - int recordIndex; + NSComparisonResult compare; + int recordIndex, secondsOffsetFromGMT; newRecord = nil; recurrenceId = [component recurrenceId]; - if ([dateRange containsDate: recurrenceId]) + if (tz) + { + // The following adjustment is necessary for floating all-day events. + // For example, the recurrence-id 20120523T000000Z for timezone -0400 + // will become 20120523T000400Z + secondsOffsetFromGMT = [tz secondsFromGMTForDate: recurrenceId]; + recurrenceId = (NSCalendarDate *) [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 + seconds:-secondsOffsetFromGMT]; + } + + compare = [[dateRange startDate] compare: recurrenceId]; + if ((compare == NSOrderedAscending || compare == NSOrderedSame) && + [[dateRange endDate] compare: recurrenceId] == NSOrderedDescending) { recordIndex = [self _indexOfRecordMatchingDate: recurrenceId inArray: ma]; @@ -799,7 +813,9 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir oldRecord = [ma objectAtIndex: recordIndex]; [newRecord setObject: [oldRecord objectForKey: @"c_recurrence_id"] forKey: @"c_recurrence_id"]; - +// [newRecord setObject: [NSNumber numberWithInt: [recurrenceId timeIntervalSince1970]] +// forKey: @"c_recurrence_id"]; + // The first instance date is added to the dictionary so it can // be used by UIxCalListingActions to compute the DST offset. [newRecord setObject: [fir startDate] forKey: @"cycleStartDate"]; @@ -838,6 +854,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir - (void) _appendCycleExceptionsFromRow: (NSDictionary *) row firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir forRange: (NGCalendarDateRange *) dateRange + withTimeZone: (NSTimeZone *) tz toArray: (NSMutableArray *) ma { NSArray *elements, *components; @@ -859,6 +876,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir firstInstanceCalendarDateRange: fir fromRow: row forRange: dateRange + withTimeZone: tz toArray: ma]; } } @@ -877,20 +895,19 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir intoArray: (NSMutableArray *) theRecords { NSMutableDictionary *row, *fixedRow; - NSMutableArray *records, *newExDates; + NSMutableArray *records; NSDictionary *cycleinfo; - NSEnumerator *exDatesList; NGCalendarDateRange *firstRange, *recurrenceRange, *oneRange; NSArray *rules, *exRules, *exDates, *ranges; NSArray *elements, *components; NSString *content; - NSCalendarDate *checkStartDate, *checkEndDate, *firstStartDate, - *firstEndDate; + NSCalendarDate *checkStartDate, *checkEndDate, *firstStartDate, *firstEndDate; + NSTimeZone *allDayTimeZone; iCalDateTime *dtstart; iCalEvent *component; iCalTimeZone *eventTimeZone; unsigned count, max, offset; - id exDate; + id tz; content = [theRecord objectForKey: @"c_cycleinfo"]; if (![content isNotNull]) @@ -910,7 +927,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir rules = [cycleinfo objectForKey: @"rules"]; exRules = [cycleinfo objectForKey: @"exRules"]; exDates = [cycleinfo objectForKey: @"exDates"]; - + eventTimeZone = allDayTimeZone = tz = nil; + row = [self fixupRecord: theRecord]; [row removeObjectForKey: @"c_cycleinfo"]; [row setObject: sharedYes forKey: @"isRecurrentEvent"]; @@ -945,12 +963,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir recurrenceRange = [NGCalendarDateRange calendarDateRangeWithStartDate: checkStartDate endDate: checkEndDate]; - // Adjust the exception dates - exDates = [eventTimeZone computedDatesForStrings: exDates]; - - // Adjust the recurrence rules "until" dates - rules = [component recurrenceRulesWithTimeZone: eventTimeZone]; - exRules = [component exceptionRulesWithTimeZone: eventTimeZone]; } else { @@ -959,29 +971,30 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { // The event lasts all-day and has no timezone (floating); we convert the range of the first event // to the user's timezone - offset = [timeZone secondsFromGMTForDate: [firstRange startDate]]; + allDayTimeZone = timeZone; + offset = [allDayTimeZone secondsFromGMTForDate: [firstRange startDate]]; firstStartDate = [[firstRange startDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:-offset]; firstEndDate = [[firstRange endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:-offset]; - [firstStartDate setTimeZone: timeZone]; - [firstEndDate setTimeZone: timeZone]; + [firstStartDate setTimeZone: allDayTimeZone]; + [firstEndDate setTimeZone: allDayTimeZone]; firstRange = [NGCalendarDateRange calendarDateRangeWithStartDate: firstStartDate endDate: firstEndDate]; - - // Adjust the exception dates - exDatesList = [exDates objectEnumerator]; - newExDates = [NSMutableArray arrayWithCapacity: [exDates count]]; - while ((exDate = [exDatesList nextObject])) - { - exDate = [[exDate asCalendarDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 - seconds:-offset]; - [newExDates addObject: exDate]; - } - exDates = newExDates; } } - + + tz = eventTimeZone? eventTimeZone : allDayTimeZone; + if (tz) + { + // Adjust the exception dates + exDates = [component exceptionDatesWithTimeZone: tz]; + + // Adjust the recurrence rules "until" dates + rules = [component recurrenceRulesWithTimeZone: tz]; + exRules = [component exceptionRulesWithTimeZone: tz]; + } + // Calculate the occurrences for the given range records = [NSMutableArray array]; ranges = [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: recurrenceRange @@ -1004,6 +1017,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [self _appendCycleExceptionsFromRow: row firstInstanceCalendarDateRange: firstRange forRange: theRange + withTimeZone: allDayTimeZone toArray: records]; [theRecords addObjectsFromArray: records]; diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 0b3ed7907..2bedbaa9d 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -399,8 +399,8 @@ static inline BOOL _occurenceHasID (iCalRepeatableEntityObject *occurence, recID = [lookupName substringFromIndex: 9]; occurence = [self lookupOccurence: recID]; if (occurence) - isNewOccurence = NO; - else + isNewOccurence = NO; + else { occurence = [self newOccurenceWithID: recID]; isNewOccurence = YES; diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index bcac3cdfa..7d3c78cee 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -513,7 +513,7 @@ [dateFormatter formattedTime: eventStartDate], @"startTime", [dateFormatter formattedDate: eventEndDate], @"endDate", [dateFormatter formattedTime: eventEndDate], @"endTime", - ([event hasRecurrenceRules] ? @"1": @"0"), @"isRecurring", + //([event hasRecurrenceRules] ? @"1": @"0"), @"isRecurring", ([event isAllDay] ? @"1": @"0"), @"isAllDay", [event summary], @"summary", [event location], @"location",