sogo/SOPE/NGCards/iCalTimeZonePeriod.m
Wolfgang Sourdeau 58fd525601 Monotone-Parent: 00c44c219ebc45d53f4b71a1825bc55315546793
Monotone-Revision: 54efe8046f7359444a19149b1c5e4ed19262c14e

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2010-03-22T17:16:16
Monotone-Branch: ca.inverse.sogo
2010-03-22 17:16:16 +00:00

173 lines
4.8 KiB
Objective-C

/* iCalTimeZonePeriod.m - this file is part of SOPE
*
* Copyright (C) 2006-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import "iCalDateTime.h"
#import "iCalRecurrenceRule.h"
#import "iCalTimeZonePeriod.h"
@implementation iCalTimeZonePeriod
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"RRULE"])
tagClass = [iCalRecurrenceRule class];
else if ([classTag isEqualToString: @"DTSTART"])
tagClass = [iCalDateTime class];
else if ([classTag isEqualToString: @"TZNAME"]
|| [classTag isEqualToString: @"TZOFFSETFROM"]
|| [classTag isEqualToString: @"TZOFFSETTO"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
- (int) _secondsOfOffset: (NSString *) offsetName
{
NSString *offsetTo;
BOOL negative;
NSRange cursor;
unsigned int length;
unsigned int seconds;
seconds = 0;
offsetTo = [[self uniqueChildWithTag: offsetName]
value: 0];
length = [offsetTo length];
negative = [offsetTo hasPrefix: @"-"];
if (negative)
{
length--;
cursor = NSMakeRange(1, 2);
}
else if ([offsetTo hasPrefix: @"+"])
{
length--;
cursor = NSMakeRange(1, 2);
}
else
cursor = NSMakeRange(0, 2);
seconds = 3600 * [[offsetTo substringWithRange: cursor] intValue];
cursor.location += 2;
seconds += 60 * [[offsetTo substringWithRange: cursor] intValue];
if (length == 6)
{
cursor.location += 2;
seconds += [[offsetTo substringWithRange: cursor] intValue];
}
return ((negative) ? -seconds : seconds);
}
- (unsigned int) dayOfWeekFromRruleDay: (iCalWeekDay) day
{
unsigned int dayOfWeek;
dayOfWeek = 0;
while (day >> (dayOfWeek + 1))
dayOfWeek++;
return dayOfWeek;
}
- (NSCalendarDate *) startDate
{
return [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]
dateTime];
}
/* This method returns the date corresponding for to the start of the period
in the year of the reference date. */
- (NSCalendarDate *) _occurenceForDate: (NSCalendarDate *) refDate
byRRule: (iCalRecurrenceRule *) rrule
{
NSCalendarDate *tmpDate;
NSString *byDay;
int dayOfWeek, dateDayOfWeek, offset, pos;
NSCalendarDate *tzStart;
byDay = [rrule namedValue: @"byday"];
dayOfWeek = [self dayOfWeekFromRruleDay: [rrule byDayMask]];
pos = [[byDay substringToIndex: 2] intValue];
if (!pos)
/* if byday = "SU", instead of "1SU"... */
pos = 1;
tzStart = [self startDate];
[tzStart setTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [NSCalendarDate dateWithYear: [refDate yearOfCommonEra]
month: [[rrule namedValue: @"bymonth"] intValue]
day: 1 hour: [tzStart hourOfDay]
minute: [tzStart minuteOfHour] second: 0
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
day: 0 hour: 0 minute: 0
second: -[self _secondsOfOffset: @"tzoffsetfrom"]];
dateDayOfWeek = [tmpDate dayOfWeek];
/* If the day of the time change is "-XSU", we need to determine whether the
first day of next month is in the same week. In practice, as most time
changes occurs on sundays, it will be false only when that first day is a
sunday, but we want to remain algorithmically exact. */
if (dateDayOfWeek > dayOfWeek && pos < 0)
pos++;
offset = (dayOfWeek - dateDayOfWeek) + (pos * 7);
tmpDate = [tmpDate addYear: 0 month: 0 day: offset
hour: 0 minute: 0 second: 0];
return tmpDate;
}
- (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate;
{
NSCalendarDate *tmpDate;
iCalRecurrenceRule *rrule;
rrule = (iCalRecurrenceRule *) [self uniqueChildWithTag: @"rrule"];
if ([rrule isVoid])
tmpDate
= [(iCalDateTime *) [self uniqueChildWithTag: @"dtstart"] dateTime];
else
tmpDate = [self _occurenceForDate: refDate byRRule: rrule];
return tmpDate;
}
- (int) secondsOffsetFromGMT
{
return [self _secondsOfOffset: @"tzoffsetto"];
}
@end