diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index c2b9ea195..17345a95a 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -23,6 +23,7 @@ #import #import #import +#import #import #import #import @@ -607,27 +608,48 @@ static Class sogoAppointmentFolderKlass = Nil; - (NSMutableDictionary *) fixupCycleRecord: (NSDictionary *) _record cycleRange: (NGCalendarDateRange *) _r + firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir + forViewRange: (NGCalendarDateRange *) _viewRange { NSMutableDictionary *md; NSNumber *dateSecs; id tmp; + signed int daylightOffset; md = [[_record mutableCopy] autorelease]; + daylightOffset = 0; /* cycle is in _r. We also have to override the c_startdate/c_enddate with the date values of the reccurence since we use those when displaying events in SOGo Web */ + tmp = [_r startDate]; + if ([timeZone isDaylightSavingTimeForDate: tmp] != [timeZone isDaylightSavingTimeForDate: [_viewRange startDate]]) + // For the event's start/end dates, compute the daylight saving time + // offset with respect to the view period. + daylightOffset = (signed int)[timeZone secondsFromGMTForDate: tmp] + - (signed int)[timeZone secondsFromGMTForDate: [_viewRange startDate]]; + [tmp setTimeZone: timeZone]; [md setObject: tmp forKey: @"startDate"]; - dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970]]; + dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970] + daylightOffset]; [md setObject: dateSecs forKey: @"c_startdate"]; - [md setObject: dateSecs forKey: @"c_recurrence_id"]; tmp = [_r endDate]; [tmp setTimeZone: timeZone]; [md setObject: tmp forKey: @"endDate"]; - dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970]]; + dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970] + daylightOffset]; [md setObject: dateSecs forKey: @"c_enddate"]; + + tmp = [_r startDate]; + if ([timeZone isDaylightSavingTimeForDate: tmp] != [timeZone isDaylightSavingTimeForDate: [_fir startDate]]) + // For the event's recurrence id, compute the daylight saving time + // offset with respect to the first occurrence of the recurring event. + daylightOffset = (signed int)[timeZone secondsFromGMTForDate: tmp] + - (signed int)[timeZone secondsFromGMTForDate: [_fir startDate]]; + else + daylightOffset = 0; + dateSecs = [NSNumber numberWithInt: [tmp timeIntervalSince1970] + daylightOffset]; + [md setObject: dateSecs forKey: @"c_recurrence_id"]; return md; } @@ -672,6 +694,7 @@ static Class sogoAppointmentFolderKlass = Nil; } - (void) _appendCycleException: (iCalRepeatableEntityObject *) component +firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir fromRow: (NSDictionary *) row forRange: (NGCalendarDateRange *) dateRange toArray: (NSMutableArray *) ma @@ -681,9 +704,20 @@ static Class sogoAppointmentFolderKlass = Nil; NSDictionary *oldRecord; NGCalendarDateRange *newRecordRange; int recordIndex; + signed int daylightOffset; newRecord = nil; recurrenceId = [component recurrenceId]; + + if ([timeZone isDaylightSavingTimeForDate: recurrenceId] != [timeZone isDaylightSavingTimeForDate: [fir startDate]]) + { + // For the event's recurrence id, compute the daylight saving time + // offset with respect to the first occurrence of the recurring event. + daylightOffset = (signed int)[timeZone secondsFromGMTForDate: [fir startDate]] + - (signed int)[timeZone secondsFromGMTForDate: recurrenceId]; + recurrenceId = [recurrenceId dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset]; + } + if ([dateRange containsDate: recurrenceId]) { recordIndex = [self _indexOfRecordMatchingDate: recurrenceId @@ -726,6 +760,7 @@ static Class sogoAppointmentFolderKlass = Nil; } - (void) _appendCycleExceptionsFromRow: (NSDictionary *) row + firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir forRange: (NGCalendarDateRange *) dateRange toArray: (NSMutableArray *) ma { @@ -743,6 +778,7 @@ static Class sogoAppointmentFolderKlass = Nil; max = [components count]; for (count = 1; count < max; count++) [self _appendCycleException: [components objectAtIndex: count] + firstInstanceCalendarDateRange: fir fromRow: row forRange: dateRange toArray: ma]; @@ -802,12 +838,16 @@ static Class sogoAppointmentFolderKlass = Nil; for (i = 0; i < count; i++) { rRange = [ranges objectAtIndex: i]; - fixedRow = [self fixupCycleRecord: row cycleRange: rRange]; + fixedRow = [self fixupCycleRecord: row + cycleRange: rRange + firstInstanceCalendarDateRange: fir + forViewRange: _r]; if (fixedRow) [recordArray addObject: fixedRow]; } [self _appendCycleExceptionsFromRow: row + firstInstanceCalendarDateRange: fir forRange: _r toArray: recordArray]; diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 0ca0f4b94..d0d6a3bbc 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -230,6 +230,7 @@ _occurenceHasID (iCalRepeatableEntityObject *occurence, NSString *recID) recDate = [NSCalendarDate dateWithTimeIntervalSince1970: [recID intValue]]; masterOccurence = [self component: NO secure: NO]; + if ([masterOccurence doesOccurOnDate: recDate]) { newOccurence = [masterOccurence mutableCopy]; diff --git a/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m b/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m index 8411d9d90..1e69a1d13 100644 --- a/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m +++ b/SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.m @@ -115,13 +115,7 @@ doesOccur = [self isRecurrent]; if (doesOccur) - { -// tz = [occurenceDate timeZone]; -// if ([tz isDaylightSavingTimeForDate: occurenceDate] != [tz isDaylightSavingTimeForDate: [self startDate]]) { -// daylightOffset = [tz secondsFromGMTForDate: occurenceDate] - [tz secondsFromGMTForDate: [self startDate]]; -// occurenceDate = [occurenceDate dateByAddingYears: 0 months: 0 days: 0 hours: 0 minutes: 0 seconds: daylightOffset]; -// } - + { endDate = [occurenceDate addTimeInterval: [self occurenceInterval]]; checkRange = [NGCalendarDateRange calendarDateRangeWithStartDate: occurenceDate endDate: endDate]; diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index a7583996e..1d9410a9f 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -24,6 +24,7 @@ #import #import +#import #import #import @@ -224,12 +225,35 @@ } else { + NSCalendarDate *firstDate; + NSTimeZone *timeZone; + iCalEvent *master; + signed int daylightOffset; + startDate = [event startDate]; + daylightOffset = 0; + + if ([co isNew] && [co isKindOfClass: [SOGoAppointmentOccurence class]]) + { + // We are creating a new exception in a recurrent event -- compute the daylight + // saving time with respect to the first occurrence of the recurrent event. + master = (iCalEvent*)[[event parent] firstChildWithTag: @"vevent"]; + firstDate = [master startDate]; + timeZone = [[context activeUser] timeZone]; + + if ([timeZone isDaylightSavingTimeForDate: startDate] != [timeZone isDaylightSavingTimeForDate: firstDate]) + { + daylightOffset = (signed int)[timeZone secondsFromGMTForDate: firstDate] + - (signed int)[timeZone secondsFromGMTForDate: startDate]; + startDate = [startDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset]; + } + } + isAllDay = [event isAllDay]; if (isAllDay) endDate = [[event endDate] dateByAddingYears: 0 months: 0 days: -1]; else - endDate = [event endDate]; + endDate = [[event endDate] dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset]; isTransparent = ![event isOpaque]; } @@ -359,21 +383,41 @@ { WOResponse *result; NSDictionary *data; + NSCalendarDate *firstDate, *eventDate; + NSTimeZone *timeZone; SOGoDateFormatter *dateFormatter; SOGoUser *user; - NSCalendarDate *startDate; + SOGoCalendarComponent *co; + iCalEvent *master; + signed int daylightOffset; + + [self event]; result = [context response]; user = [context activeUser]; + timeZone = [user timeZone]; dateFormatter = [user dateFormatterInContext: context]; + eventDate = [event startDate]; + [eventDate setTimeZone: timeZone]; + co = [self clientObject]; + + if ([co isNew] && [co isKindOfClass: [SOGoAppointmentOccurence class]]) + { + // This is a new exception in a recurrent event -- compute the daylight + // saving time with respect to the first occurrence of the recurrent event. + master = (iCalEvent*)[[event parent] firstChildWithTag: @"vevent"]; + firstDate = [master startDate]; - [self event]; - startDate = [[event startDate] copy]; - [startDate setTimeZone: [user timeZone]]; - + if ([timeZone isDaylightSavingTimeForDate: eventDate] != [timeZone isDaylightSavingTimeForDate: firstDate]) + { + daylightOffset = (signed int)[timeZone secondsFromGMTForDate: firstDate] + - (signed int)[timeZone secondsFromGMTForDate: eventDate]; + eventDate = [eventDate dateByAddingYears:0 months:0 days:0 hours:0 minutes:0 seconds:daylightOffset]; + } + } data = [NSDictionary dictionaryWithObjectsAndKeys: - [dateFormatter formattedDate: startDate], @"startDate", - [dateFormatter formattedTime: startDate], @"startTime", + [dateFormatter formattedDate: eventDate], @"startDate", + [dateFormatter formattedTime: eventDate], @"startTime", ([event hasRecurrenceRules]? @"1": @"0"), @"isReccurent", ([event isAllDay] ? @"1": @"0"), @"isAllDay", [event summary], @"summary", @@ -382,7 +426,6 @@ nil]; [result appendContentString: [data jsonRepresentation]]; - [startDate release]; return result; }