Monotone-Parent: 4e8caa9222644e6820515bbf312f74dbd372c2fc

Monotone-Revision: 25c172f93ef4ab6ada0aeb6ff4267e98aef8b719

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2008-12-10T18:57:55
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau 2008-12-10 18:57:55 +00:00
parent b8b4c6b5d3
commit ff33d95a42
4 changed files with 526 additions and 469 deletions

View file

@ -130,23 +130,20 @@
- (NSCalendarDate *) lastInstanceStartDate - (NSCalendarDate *) lastInstanceStartDate
{ {
NSCalendarDate *firStart, *lastInstanceStartDate;
if ([rrule repeatCount] > 0) if ([rrule repeatCount] > 0)
{ {
long jnFirst, jnRuleLast;
NSCalendarDate *firStart, *until;
firStart = [firstRange startDate]; firStart = [firstRange startDate];
jnFirst = [firStart julianNumber];
jnRuleLast = ([rrule repeatInterval] * lastInstanceStartDate = [firStart dateByAddingYears: 0 months: 0
[rrule repeatCount]) + days: ([rrule repeatInterval]
jnFirst; * [rrule repeatCount])];
until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
until = [until hour: [firStart hourOfDay]
minute: [firStart minuteOfHour]
second: [firStart secondOfMinute]];
return until;
} }
return [super lastInstanceStartDate]; else
lastInstanceStartDate = [super lastInstanceStartDate];
return lastInstanceStartDate;
} }
@end /* iCalDailyRecurrenceCalculator */ @end /* iCalDailyRecurrenceCalculator */

View file

@ -32,8 +32,10 @@
#import "NSCalendarDate+ICal.h" #import "NSCalendarDate+ICal.h"
#import <string.h> #import <string.h>
@interface iCalRecurrenceCalculator(PrivateAPI) @interface iCalRecurrenceCalculator (PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
- (NSCalendarDate *) lastInstanceStartDate;
@end @end
// #define HEAVY_DEBUG 1 // #define HEAVY_DEBUG 1
@ -44,7 +46,8 @@ typedef BOOL NGMonthSet[12];
typedef BOOL NGMonthDaySet[32]; // 0 is unused typedef BOOL NGMonthDaySet[32]; // 0 is unused
static void static void
NGMonthDaySet_clear(NGMonthDaySet *daySet) NGMonthDaySet_clear (NGMonthDaySet *daySet)
{ {
register unsigned i; register unsigned i;
@ -53,49 +56,58 @@ NGMonthDaySet_clear(NGMonthDaySet *daySet)
} }
static void static void
NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new, NGMonthDaySet_copyOrUnion (NGMonthDaySet *base, NGMonthDaySet *new,
BOOL doCopy) BOOL doCopy)
{ {
register unsigned i; register unsigned i;
if (doCopy) if (doCopy)
memcpy(base, new, sizeof(NGMonthDaySet)); memcpy (base, new, sizeof (NGMonthDaySet));
else { else
for (i = 1; i <= 31; i++) { {
if (!(*new)[i]) for (i = 1; i <= 31; i++)
{
if (! (*new)[i])
(*base)[i] = NO; (*base)[i] = NO;
} }
} }
} }
static BOOL NGMonthDaySet_fillWithByMonthDay(NGMonthDaySet *daySet, static BOOL NGMonthDaySet_fillWithByMonthDay (NGMonthDaySet *daySet,
NSArray *byMonthDay) NSArray *byMonthDay)
{ {
/* list of days in the month */ /* list of days in the month */
unsigned i, count; unsigned i, count;
BOOL ok; BOOL ok;
NGMonthDaySet_clear(daySet); NGMonthDaySet_clear (daySet);
for (i = 0, count = [byMonthDay count], ok = YES; i < count; i++) { for (i = 0, count = [byMonthDay count], ok = YES; i < count; i++)
{
int dayInMonth; /* -31..-1 and 1..31 */ int dayInMonth; /* -31..-1 and 1..31 */
if ((dayInMonth = [[byMonthDay objectAtIndex:i] intValue]) == 0) { if ((dayInMonth = [[byMonthDay objectAtIndex: i] intValue]) == 0)
{
ok = NO; ok = NO;
continue; /* invalid value */ continue; /* invalid value */
} }
if (dayInMonth > 31) { if (dayInMonth > 31)
{
ok = NO; ok = NO;
continue; /* error, value to large */ continue; /* error, value to large */
} }
if (dayInMonth < -31) { if (dayInMonth < -31)
{
ok = NO; ok = NO;
continue; /* error, value to large */ continue; /* error, value to large */
} }
/* adjust negative days */ /* adjust negative days */
if (dayInMonth < 0) { if (dayInMonth < 0)
{
/* eg: -1 == last day in month, 30 days => 30 */ /* eg: -1 == last day in month, 30 days => 30 */
dayInMonth = 32 - dayInMonth /* because we count from 1 */; dayInMonth = 32 - dayInMonth /* because we count from 1 */;
} }
@ -105,8 +117,10 @@ static BOOL NGMonthDaySet_fillWithByMonthDay(NGMonthDaySet *daySet,
return ok; return ok;
} }
static inline unsigned iCalDoWForNSDoW(int dow) { static inline unsigned iCalDoWForNSDoW (int dow)
switch (dow) { {
switch (dow)
{
case 0: return iCalWeekDaySunday; case 0: return iCalWeekDaySunday;
case 1: return iCalWeekDayMonday; case 1: return iCalWeekDayMonday;
case 2: return iCalWeekDayTuesday; case 2: return iCalWeekDayTuesday;
@ -125,11 +139,12 @@ static NSString *dowEN[8] = {
}; };
#endif #endif
static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet, static void NGMonthDaySet_fillWithByDayX (NGMonthDaySet *daySet,
unsigned dayMask, unsigned dayMask,
unsigned firstDoWInMonth, unsigned firstDoWInMonth,
unsigned numberOfDaysInMonth, unsigned numberOfDaysInMonth,
int occurrence1) int occurrence1)
{ {
// TODO: this is called 'X' because the API doesn't allow for full iCalendar // TODO: this is called 'X' because the API doesn't allow for full iCalendar
// functionality. The daymask must be a list of occurence+dow // functionality. The daymask must be a list of occurence+dow
@ -137,13 +152,16 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
register int dow; /* current day of the week */ register int dow; /* current day of the week */
int occurrences[7] = { 0, 0, 0, 0, 0, 0, 0 } ; int occurrences[7] = { 0, 0, 0, 0, 0, 0, 0 } ;
NGMonthDaySet_clear(daySet); NGMonthDaySet_clear (daySet);
if (occurrence1 >= 0) { if (occurrence1 >= 0)
for (dayInMonth = 1, dow = firstDoWInMonth; dayInMonth<=31; dayInMonth++) { {
for (dayInMonth = 1, dow = firstDoWInMonth; dayInMonth<=31; dayInMonth++)
{
// TODO: complete me // TODO: complete me
if (dayMask & iCalDoWForNSDoW(dow)) { if (dayMask & iCalDoWForNSDoW (dow))
{
if (occurrence1 == 0) if (occurrence1 == 0)
(*daySet)[dayInMonth] = YES; (*daySet)[dayInMonth] = YES;
else { /* occurrence1 > 0 */ else { /* occurrence1 > 0 */
@ -157,7 +175,8 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1); dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
} }
} }
else { else
{
int lastDoWInMonthSet; int lastDoWInMonthSet;
/* get the last dow in the set (not necessarily the month!) */ /* get the last dow in the set (not necessarily the month!) */
@ -167,16 +186,17 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
lastDoWInMonthSet = dow; lastDoWInMonthSet = dow;
#if HEAVY_DEBUG #if HEAVY_DEBUG
NSLog(@"LAST DOW IN SET: %i / %@", NSLog (@"LAST DOW IN SET: %i / %@",
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]); lastDoWInMonthSet, dowEN[lastDoWInMonthSet]);
#endif #endif
/* start at the end of the set */ /* start at the end of the set */
for (dayInMonth = numberOfDaysInMonth, dow = lastDoWInMonthSet; for (dayInMonth = numberOfDaysInMonth, dow = lastDoWInMonthSet;
dayInMonth >= 1; dayInMonth--) { dayInMonth >= 1; dayInMonth--)
{
// TODO: complete me // TODO: complete me
#if HEAVY_DEBUG #if HEAVY_DEBUG
NSLog(@" CHECK day-of-month %02i, " NSLog (@" CHECK day-of-month %02i, "
@" dow=%i/%@ (first=%i/%@, last=%i/%@)", @" dow=%i/%@ (first=%i/%@, last=%i/%@)",
dayInMonth, dayInMonth,
dow, dowEN[dow], dow, dowEN[dow],
@ -185,16 +205,18 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
); );
#endif #endif
if (dayMask & iCalDoWForNSDoW(dow)) { if (dayMask & iCalDoWForNSDoW (dow))
{
occurrences[dow] = occurrences[dow] + 1; occurrences[dow] = occurrences[dow] + 1;
#if HEAVY_DEBUG #if HEAVY_DEBUG
NSLog(@" MATCH %i/%@ count: %i occurences=%i", NSLog (@" MATCH %i/%@ count: %i occurences=%i",
dow, dowEN[dow], occurrences[dow], occurrence1); dow, dowEN[dow], occurrences[dow], occurrence1);
#endif #endif
if (occurrences[dow] == -occurrence1) { if (occurrences[dow] == -occurrence1)
{
#if HEAVY_DEBUG #if HEAVY_DEBUG
NSLog(@" COUNT MATCH"); NSLog (@" COUNT MATCH");
#endif #endif
(*daySet)[dayInMonth] = YES; (*daySet)[dayInMonth] = YES;
} }
@ -205,10 +227,11 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
} }
} }
- (BOOL)_addInstanceWithStartDate:(NSCalendarDate *)_startDate - (BOOL) _addInstanceWithStartDate: (NSCalendarDate *)_startDate
limitDate:(NSCalendarDate *)_until limitDate: (NSCalendarDate *)_until
limitRange:(NGCalendarDateRange *)_r limitRange: (NGCalendarDateRange *)_r
toArray:(NSMutableArray *)_ranges toArray: (NSMutableArray *)_ranges
{ {
NGCalendarDateRange *r; NGCalendarDateRange *r;
NSCalendarDate *end; NSCalendarDate *end;
@ -218,29 +241,32 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
// TODO: I think we should check in here whether we succeeded the // TODO: I think we should check in here whether we succeeded the
// repeatCount. Currently we precalculate that info in the // repeatCount. Currently we precalculate that info in the
// -lastInstanceStartDate method. // -lastInstanceStartDate method.
if (_until != nil) { if (_until != nil)
{
/* Note: the 'until' in the rrule is inclusive as per spec */ /* Note: the 'until' in the rrule is inclusive as per spec */
if ([_until compare:_startDate] == NSOrderedAscending) if ([_until compare: _startDate] == NSOrderedAscending)
/* start after until */ /* start after until */
return NO; /* Note: we assume that the algorithm is sequential */ return NO; /* Note: we assume that the algorithm is sequential */
} }
/* create end date */ /* create end date */
end = [_startDate addTimeInterval:[self->firstRange duration]]; end = [_startDate addTimeInterval: [firstRange duration]];
[end setTimeZone:[_startDate timeZone]]; [end setTimeZone: [_startDate timeZone]];
/* create range and check whether its in the requested range */ /* create range and check whether its in the requested range */
r = [[NGCalendarDateRange alloc] initWithStartDate:_startDate endDate:end]; r = [[NGCalendarDateRange alloc] initWithStartDate: _startDate endDate: end];
if ([_r containsDateRange:r]) if ([_r containsDateRange: r])
[_ranges addObject:r]; [_ranges addObject: r];
[r release]; r = nil; [r release]; r = nil;
return YES; return YES;
} }
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{ - (NSArray *)
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
{
/* main entry */ /* main entry */
// TODO: check whether this is OK for multiday-events! // TODO: check whether this is OK for multiday-events!
NSMutableArray *ranges; NSMutableArray *ranges;
@ -257,44 +283,46 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
NSArray *byMonthDay; // array of ints (-31..-1 and 1..31) NSArray *byMonthDay; // array of ints (-31..-1 and 1..31)
NGMonthDaySet byMonthDaySet; NGMonthDaySet byMonthDaySet;
eventStartDate = [self->firstRange startDate]; eventStartDate = [firstRange startDate];
eventDayOfMonth = [eventStartDate dayOfMonth]; eventDayOfMonth = [eventStartDate dayOfMonth];
timeZone = [eventStartDate timeZone]; timeZone = [eventStartDate timeZone];
rStart = [_r startDate]; rStart = [_r startDate];
rEnd = [_r endDate]; rEnd = [_r endDate];
interval = [self->rrule repeatInterval]; interval = [rrule repeatInterval];
until = [self lastInstanceStartDate]; // TODO: maybe replace until = [self lastInstanceStartDate]; // TODO: maybe replace
byMonthDay = [self->rrule byMonthDay]; byMonthDay = [rrule byMonthDay];
/* check whether the range to be processed is beyond the 'until' date */ /* check whether the range to be processed is beyond the 'until' date */
if (until) { if (until)
if ([until compare:rStart] == NSOrderedAscending) /* until before start */ {
if ([until compare: rStart] == NSOrderedAscending) /* until before start */
return nil; return nil;
if ([until compare:rEnd] == NSOrderedDescending) /* end before until */ if ([until compare: rEnd] == NSOrderedDescending) /* end before until */
rEnd = until; // TODO: why is that? end is _before_ until? rEnd = until; // TODO: why is that? end is _before_ until?
} }
/* precalculate month days (same for all instances) */ /* precalculate month days (same for all instances) */
if (byMonthDay) { if (byMonthDay)
{
#if HEAVY_DEBUG #if HEAVY_DEBUG
NSLog(@"byMonthDay: %@", byMonthDay); NSLog (@"byMonthDay: %@", byMonthDay);
#endif #endif
NGMonthDaySet_fillWithByMonthDay(&byMonthDaySet, byMonthDay); NGMonthDaySet_fillWithByMonthDay (&byMonthDaySet, byMonthDay);
} }
// TODO: I think the 'diff' is to skip recurrence which are before the // TODO: I think the 'diff' is to skip recurrence which are before the
// requested range. Not sure whether this is actually possible, eg // requested range. Not sure whether this is actually possible, eg
// the repeatCount must be processed from the start. // the repeatCount must be processed from the start.
diff = [eventStartDate monthsBetweenDate:rStart]; diff = [eventStartDate monthsBetweenDate: rStart];
if ((diff != 0) && [rStart compare:eventStartDate] == NSOrderedAscending) if ((diff != 0) && [rStart compare: eventStartDate] == NSOrderedAscending)
diff = -diff; diff = -diff;
numberOfMonthsInRange = [rStart monthsBetweenDate:rEnd] + 1; numberOfMonthsInRange = [rStart monthsBetweenDate: rEnd] + 1;
ranges = [NSMutableArray arrayWithCapacity:numberOfMonthsInRange]; ranges = [NSMutableArray arrayWithCapacity: numberOfMonthsInRange];
/* /*
Note: we do not add 'eventStartDate', this is intentional, the event date Note: we do not add 'eventStartDate', this is intentional, the event date
@ -303,7 +331,8 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
*/ */
for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange; for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange;
monthIdxInRange++) { monthIdxInRange++)
{
NSCalendarDate *cursor; NSCalendarDate *cursor;
unsigned numDaysInMonth; unsigned numDaysInMonth;
int monthIdxInRecurrence, dom; int monthIdxInRecurrence, dom;
@ -329,10 +358,10 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
Note: the function below adds exactly a month, eg: Note: the function below adds exactly a month, eg:
2007-01-30 + 1month => 2007-02-*28*!! 2007-01-30 + 1month => 2007-02-*28*!!
*/ */
cursor = [eventStartDate dateByAddingYears:0 cursor = [eventStartDate dateByAddingYears: 0
months:(diff + monthIdxInRange) months: (diff + monthIdxInRange)
days:0]; days: 0];
[cursor setTimeZone:timeZone]; [cursor setTimeZone: timeZone];
numDaysInMonth = [cursor numberOfDaysInMonth]; numDaysInMonth = [cursor numberOfDaysInMonth];
@ -346,29 +375,32 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
didByFill = NO; didByFill = NO;
if (byMonthDay) { /* list of days in the month */ if (byMonthDay)
NGMonthDaySet_copyOrUnion(&monthDays, &byMonthDaySet, !didByFill); { /* list of days in the month */
NGMonthDaySet_copyOrUnion (&monthDays, &byMonthDaySet, !didByFill);
didByFill = YES; didByFill = YES;
} }
if ([self->rrule byDayMask] != 0) { // TODO: replace the mask with an array if ([rrule byDayMask] != 0)
{ // TODO: replace the mask with an array
NGMonthDaySet ruleset; NGMonthDaySet ruleset;
unsigned firstDoWInMonth; unsigned firstDoWInMonth;
firstDoWInMonth = [[cursor firstDayOfMonth] dayOfWeek]; firstDoWInMonth = [[cursor firstDayOfMonth] dayOfWeek];
NGMonthDaySet_fillWithByDayX(&ruleset, NGMonthDaySet_fillWithByDayX (&ruleset,
[self->rrule byDayMask], [rrule byDayMask],
firstDoWInMonth, firstDoWInMonth,
[cursor numberOfDaysInMonth], [cursor numberOfDaysInMonth],
[self->rrule byDayOccurence1]); [rrule byDayOccurence1]);
NGMonthDaySet_copyOrUnion(&monthDays, &ruleset, !didByFill); NGMonthDaySet_copyOrUnion (&monthDays, &ruleset, !didByFill);
didByFill = YES; didByFill = YES;
} }
if (!didByFill) { if (!didByFill)
{
/* no rules applied, take the dayOfMonth of the startDate */ /* no rules applied, take the dayOfMonth of the startDate */
NGMonthDaySet_clear(&monthDays); NGMonthDaySet_clear (&monthDays);
monthDays[eventDayOfMonth] = YES; monthDays[eventDayOfMonth] = YES;
} }
@ -388,7 +420,8 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
cursor[2]: 2007-02-28 <== Note: we have February! cursor[2]: 2007-02-28 <== Note: we have February!
*/ */
for (dom = 1, doCont = YES; dom <= numDaysInMonth && doCont; dom++) { for (dom = 1, doCont = YES; dom <= numDaysInMonth && doCont; dom++)
{
NSCalendarDate *start; NSCalendarDate *start;
if (!monthDays[dom]) if (!monthDays[dom])
@ -416,14 +449,16 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
start was: 2007-01-30 start was: 2007-01-30
cursor will be: 2007-02-28 cursor will be: 2007-02-28
*/ */
if (eventDayOfMonth == dom) { if (eventDayOfMonth == dom)
{
start = cursor; start = cursor;
} }
else { else
{
int maxDay = int maxDay =
eventDayOfMonth > numDaysInMonth ? numDaysInMonth : eventDayOfMonth; eventDayOfMonth > numDaysInMonth ? numDaysInMonth : eventDayOfMonth;
start = [cursor dateByAddingYears:0 months:0 days:(dom - maxDay)]; start = [cursor dateByAddingYears: 0 months: 0 days: (dom - maxDay)];
} }
/* /*
@ -435,34 +470,36 @@ static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
*/ */
#if HEAVY_DEBUG #if HEAVY_DEBUG
NSLog(@"DOM %i EDOM %i NUMDAYS %i START: %@ CURSOR: %@", NSLog (@"DOM %i EDOM %i NUMDAYS %i START: %@ CURSOR: %@",
dom, eventDayOfMonth, numDaysInMonth, dom, eventDayOfMonth, numDaysInMonth,
start, cursor); start, cursor);
#endif #endif
doCont = [self _addInstanceWithStartDate:start doCont = [self _addInstanceWithStartDate: start
limitDate:until limitDate: until
limitRange:_r limitRange: _r
toArray:ranges]; toArray: ranges];
} }
if (!doCont) break; /* reached some limit */ if (!doCont) break; /* reached some limit */
} }
return ranges; return ranges;
} }
- (NSCalendarDate *)lastInstanceStartDate { - (NSCalendarDate *) lastInstanceStartDate
if ([self->rrule repeatCount] > 0) { {
if ([rrule repeatCount] > 0)
{
NSCalendarDate *until; NSCalendarDate *until;
unsigned months, interval; unsigned months, interval;
interval = [self->rrule repeatInterval]; interval = [rrule repeatInterval];
months = [self->rrule repeatCount] - 1 /* the first counts as one! */; months = [rrule repeatCount] - 1 /* the first counts as one! */;
if (interval > 0) if (interval > 0)
months *= interval; months *= interval;
until = [[self->firstRange startDate] dateByAddingYears:0 until = [[firstRange startDate] dateByAddingYears: 0
months:months months: months
days:0]; days: 0];
return until; return until;
} }
return [super lastInstanceStartDate]; return [super lastInstanceStartDate];

View file

@ -34,11 +34,11 @@
- (NSCalendarDate *) lastInstanceStartDate; - (NSCalendarDate *) lastInstanceStartDate;
- (unsigned) offsetFromSundayForJulianNumber:(long)_jn; - (unsigned) offsetFromSundayForJulianNumber: (long) _jn;
- (unsigned) offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay; - (unsigned) offsetFromSundayForWeekDay: (iCalWeekDay) _weekDay;
- (unsigned) offsetFromSundayForCurrentWeekStart; - (unsigned) offsetFromSundayForCurrentWeekStart;
- (iCalWeekDay) weekDayForJulianNumber:(long)_jn; - (iCalWeekDay) weekDayForJulianNumber: (long) _jn;
@end @end
@ -56,7 +56,7 @@
long i, jnFirst, jnStart, jnEnd, startEndCount; long i, jnFirst, jnStart, jnEnd, startEndCount;
unsigned interval, byDayMask; unsigned interval, byDayMask;
firStart = [self->firstRange startDate]; firStart = [firstRange startDate];
jnFirst = [firStart julianNumber]; jnFirst = [firStart julianNumber];
jnEnd = [[_r endDate] julianNumber]; jnEnd = [[_r endDate] julianNumber];
@ -64,21 +64,24 @@
return nil; return nil;
jnStart = [[_r startDate] julianNumber]; jnStart = [[_r startDate] julianNumber];
interval = [self->rrule repeatInterval]; interval = [rrule repeatInterval];
/* if rule is bound, check the bounds */ /* if rule is bound, check the bounds */
if (![self->rrule isInfinite]) { if (![rrule isInfinite])
{
NSCalendarDate *until; NSCalendarDate *until;
long jnRuleLast; long jnRuleLast;
until = [self->rrule untilDate]; until = [rrule untilDate];
if (until) { if (until)
if ([until compare:[_r startDate]] == NSOrderedAscending) {
if ([until compare: [_r startDate]] == NSOrderedAscending)
return nil; return nil;
jnRuleLast = [until julianNumber]; jnRuleLast = [until julianNumber];
} }
else { else
jnRuleLast = (interval * [self->rrule repeatCount] * 7) {
jnRuleLast = (interval * [rrule repeatCount] * 7)
+ jnFirst; + jnFirst;
if (jnRuleLast < jnStart) if (jnRuleLast < jnStart)
return nil; return nil;
@ -89,80 +92,91 @@
} }
startEndCount = (jnEnd - jnStart) + 1; startEndCount = (jnEnd - jnStart) + 1;
ranges = [NSMutableArray arrayWithCapacity:startEndCount]; ranges = [NSMutableArray arrayWithCapacity: startEndCount];
byDayMask = [self->rrule byDayMask]; byDayMask = [rrule byDayMask];
if (!byDayMask) { if (!byDayMask)
for (i = 0 ; i < startEndCount; i++) { {
for (i = 0 ; i < startEndCount; i++)
{
long jnCurrent; long jnCurrent;
jnCurrent = jnStart + i; jnCurrent = jnStart + i;
if (jnCurrent >= jnFirst) { if (jnCurrent >= jnFirst)
{
long jnDiff; long jnDiff;
jnDiff = jnCurrent - jnFirst; /* difference in days */ jnDiff = jnCurrent - jnFirst; /* difference in days */
if ((jnDiff % (interval * 7)) == 0) { if ((jnDiff % (interval * 7)) == 0)
{
NSCalendarDate *start, *end; NSCalendarDate *start, *end;
NGCalendarDateRange *r; NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent]; start = [NSCalendarDate dateForJulianNumber: jnCurrent];
[start setTimeZone:[firStart timeZone]]; [start setTimeZone: [firStart timeZone]];
start = [start hour: [firStart hourOfDay] start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour] minute: [firStart minuteOfHour]
second:[firStart secondOfMinute]]; second: [firStart secondOfMinute]];
end = [start addTimeInterval:[self->firstRange duration]]; end = [start addTimeInterval: [firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start r = [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate:end]; endDate: end];
if ([_r containsDateRange:r]) if ([_r containsDateRange: r])
[ranges addObject:r]; [ranges addObject: r];
} }
} }
} }
} }
else { else
{
long jnFirstWeekStart, weekStartOffset; long jnFirstWeekStart, weekStartOffset;
/* calculate jnFirst's week start - this depends on our setting of week /* calculate jnFirst's week start - this depends on our setting of week
start */ start */
weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] - weekStartOffset = [self offsetFromSundayForJulianNumber: jnFirst] -
[self offsetFromSundayForCurrentWeekStart]; [self offsetFromSundayForCurrentWeekStart];
jnFirstWeekStart = jnFirst - weekStartOffset; jnFirstWeekStart = jnFirst - weekStartOffset;
for (i = 0 ; i < startEndCount; i++) { for (i = 0 ; i < startEndCount; i++)
{
long jnCurrent; long jnCurrent;
jnCurrent = jnStart + i; jnCurrent = jnStart + i;
if (jnCurrent >= jnFirst) { if (jnCurrent >= jnFirst)
{
long jnDiff; long jnDiff;
/* we need to calculate a difference in weeks */ /* we need to calculate a difference in weeks */
jnDiff = (jnCurrent - jnFirstWeekStart) % 7; jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
if ((jnDiff % interval) == 0) { if ((jnDiff % interval) == 0)
{
BOOL isRecurrence = NO; BOOL isRecurrence = NO;
if (jnCurrent == jnFirst) { if (jnCurrent == jnFirst)
{
isRecurrence = YES; isRecurrence = YES;
} }
else { else
{
iCalWeekDay weekDay; iCalWeekDay weekDay;
weekDay = [self weekDayForJulianNumber:jnCurrent]; weekDay = [self weekDayForJulianNumber: jnCurrent];
isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO; isRecurrence = (weekDay & [rrule byDayMask]) ? YES : NO;
} }
if (isRecurrence) { if (isRecurrence)
{
NSCalendarDate *start, *end; NSCalendarDate *start, *end;
NGCalendarDateRange *r; NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent]; start = [NSCalendarDate dateForJulianNumber: jnCurrent];
[start setTimeZone:[firStart timeZone]]; [start setTimeZone: [firStart timeZone]];
start = [start hour: [firStart hourOfDay] start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour] minute: [firStart minuteOfHour]
second:[firStart secondOfMinute]]; second: [firStart secondOfMinute]];
end = [start addTimeInterval:[self->firstRange duration]]; end = [start addTimeInterval: [firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start r = [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate:end]; endDate: end];
if ([_r containsDateRange:r]) if ([_r containsDateRange: r])
[ranges addObject:r]; [ranges addObject: r];
} }
} }
} }
@ -171,20 +185,22 @@
return ranges; return ranges;
} }
- (NSCalendarDate *)lastInstanceStartDate { - (NSCalendarDate *) lastInstanceStartDate
if ([self->rrule repeatCount] > 0) { {
if ([rrule repeatCount] > 0)
{
long jnFirst, jnRuleLast; long jnFirst, jnRuleLast;
NSCalendarDate *firStart, *until; NSCalendarDate *firStart, *until;
firStart = [self->firstRange startDate]; firStart = [firstRange startDate];
jnFirst = [firStart julianNumber]; jnFirst = [firStart julianNumber];
jnRuleLast = ([self->rrule repeatInterval] * jnRuleLast = ([rrule repeatInterval] *
[self->rrule repeatCount] * 7) + [rrule repeatCount] * 7) +
jnFirst; jnFirst;
until = [NSCalendarDate dateForJulianNumber:jnRuleLast]; until = [NSCalendarDate dateForJulianNumber: jnRuleLast];
until = [until hour: [firStart hourOfDay] until = [until hour: [firStart hourOfDay]
minute:[firStart minuteOfHour] minute: [firStart minuteOfHour]
second:[firStart secondOfMinute]]; second: [firStart secondOfMinute]];
return until; return until;
} }
return [super lastInstanceStartDate]; return [super lastInstanceStartDate];

View file

@ -30,69 +30,76 @@
#import "iCalRecurrenceRule.h" #import "iCalRecurrenceRule.h"
#import "NSCalendarDate+ICal.h" #import "NSCalendarDate+ICal.h"
@interface iCalRecurrenceCalculator(PrivateAPI) @interface iCalRecurrenceCalculator (PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate; - (NSCalendarDate *) lastInstanceStartDate;
@end @end
@implementation iCalYearlyRecurrenceCalculator @implementation iCalYearlyRecurrenceCalculator
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{ - (NSArray *)
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
{
NSMutableArray *ranges; NSMutableArray *ranges;
NSCalendarDate *firStart, *rStart, *rEnd, *until; NSCalendarDate *firStart, *rStart, *rEnd, *until;
unsigned i, count, interval; unsigned i, count, interval;
int diff; int diff;
firStart = [self->firstRange startDate]; firStart = [firstRange startDate];
rStart = [_r startDate]; rStart = [_r startDate];
rEnd = [_r endDate]; rEnd = [_r endDate];
interval = [self->rrule repeatInterval]; interval = [rrule repeatInterval];
until = [self lastInstanceStartDate]; until = [self lastInstanceStartDate];
if (until) { if (until)
if ([until compare:rStart] == NSOrderedAscending) {
if ([until compare: rStart] == NSOrderedAscending)
return nil; return nil;
if ([until compare:rEnd] == NSOrderedDescending) if ([until compare: rEnd] == NSOrderedDescending)
rEnd = until; rEnd = until;
} }
diff = [firStart yearsBetweenDate:rStart]; diff = [firStart yearsBetweenDate: rStart];
if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending) if ((diff != 0) && [rStart compare: firStart] == NSOrderedAscending)
diff = -diff; diff = -diff;
count = [rStart yearsBetweenDate:rEnd] + 1; count = [rStart yearsBetweenDate: rEnd] + 1;
ranges = [NSMutableArray arrayWithCapacity:count]; ranges = [NSMutableArray arrayWithCapacity: count];
for (i = 0 ; i < count; i++) { for (i = 0 ; i < count; i++)
{
int test; int test;
test = diff + i; test = diff + i;
if ((test >= 0) && (test % interval) == 0) { if ((test >= 0) && (test % interval) == 0)
{
NSCalendarDate *start, *end; NSCalendarDate *start, *end;
NGCalendarDateRange *r; NGCalendarDateRange *r;
start = [firStart dateByAddingYears:diff + i start = [firStart dateByAddingYears: diff + i
months:0 months: 0
days:0]; days: 0];
[start setTimeZone:[firStart timeZone]]; [start setTimeZone: [firStart timeZone]];
end = [start addTimeInterval:[self->firstRange duration]]; end = [start addTimeInterval: [firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start r = [NGCalendarDateRange calendarDateRangeWithStartDate: start
endDate:end]; endDate: end];
if ([_r containsDateRange:r]) if ([_r containsDateRange: r])
[ranges addObject:r]; [ranges addObject: r];
} }
} }
return ranges; return ranges;
} }
- (NSCalendarDate *)lastInstanceStartDate { - (NSCalendarDate *) lastInstanceStartDate
if ([self->rrule repeatCount] > 0) { {
if ([rrule repeatCount] > 0)
{
NSCalendarDate *until; NSCalendarDate *until;
unsigned years, interval; unsigned years, interval;
interval = [self->rrule repeatInterval]; interval = [rrule repeatInterval];
years = [self->rrule repeatCount] * interval; years = [rrule repeatCount] * interval;
until = [[self->firstRange startDate] dateByAddingYears:years until = [[firstRange startDate] dateByAddingYears: years
months:0 months: 0
days:0]; days: 0];
return until; return until;
} }
return [super lastInstanceStartDate]; return [super lastInstanceStartDate];