Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Ical.Net.Tests/Calendars/Recurrence/RecurrenceTestCases.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,24 @@ INSTANCES:20241024,20241028,20241031
# Illegal rule part with multiple '='
RRULE:FREQ=WEEKLY;BYDAY=MO=;COUNT=3
EXCEPTION:System.ArgumentException

# The first date belongs to 2009, so after 6 years it will be 2015, which has a week 53.
RRULE:FREQ=YEARLY;BYWEEKNO=53;BYDAY=TU,SA;INTERVAL=6;UNTIL=20170101T000000Z
DTSTART:20100102T000000
INSTANCES:20100102T000000,20151229T000000,20160102T000000

# The first date belongs to 2009, so after 5 years it will be 2014, which has NO week 53.
RRULE:FREQ=YEARLY;BYWEEKNO=53;BYDAY=TU,SA;INTERVAL=5;UNTIL=20170101T000000Z
DTSTART:20100102T000000
INSTANCES:20100102T000000

# The first date belongs to 2009, so after 7 years it will be 2014, which has NO week 53.
RRULE:FREQ=YEARLY;BYWEEKNO=53;BYDAY=TU,SA;INTERVAL=7;UNTIL=20170101T000000Z
DTSTART:20100102T000000
INSTANCES:20100102T000000

# DTSTART is in 2024 but the week belongs to 2025, so after 3 years it will be 2028.
RRULE:FREQ=YEARLY;BYWEEKNO=1;BYDAY=MO,TU;INTERVAL=3;UNTIL=20320101
DTSTART:20241231
INSTANCES:20241231,20280103,20280104,20301230,20301231

5 changes: 1 addition & 4 deletions Ical.Net/Evaluation/Evaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,8 @@ protected IDateTime ConvertToIDateTime(DateTime dt, IDateTime referenceDate)

protected void IncrementDate(ref DateTime dt, RecurrencePattern pattern, int interval)
{
// FIXME: use a more specific exception.
if (interval == 0)
{
throw new Exception("Cannot evaluate with an interval of zero. Please use an interval other than zero.");
}
return;

var old = dt;
switch (pattern.Frequency)
Expand Down
47 changes: 30 additions & 17 deletions Ical.Net/Evaluation/RecurrencePatternEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,14 @@
var originalDate = DateUtil.GetSimpleDateTimeData(seed);
var seedCopy = DateUtil.GetSimpleDateTimeData(seed);

if ((pattern.Frequency == FrequencyType.Yearly) && (pattern.ByWeekNo.Count != 0))
{
// Dates in the first or last week of the year could belong weeks that belong to
// the prev/next year, in which case we must adjust that year. This is necessary
// to get the invervals right.
IncrementDate(ref seedCopy, pattern, Calendar.GetIso8601YearOfWeek(seedCopy, pattern.FirstDayOfWeek) - seedCopy.Year);
}

// optimize the start time for selecting candidates
// (only applicable where a COUNT is not specified)
if (pattern.Count == int.MinValue)
Expand Down Expand Up @@ -398,34 +406,39 @@
foreach (var weekNo in GetByWeekNoForYearNormalized(pattern, t.Year))
{
var date = t;

// Make sure we start from a reference date that is in a week that belongs to the current year.
// Its not important that the date lies in a certain week, but that the week belongs to the
// current year and that the week day is preserved.
if (date.Month == 1)
date = date.AddDays(7);
else if (date.Month >= 12)
date = date.AddDays(-7);

Check warning on line 416 in Ical.Net/Evaluation/RecurrencePatternEvaluator.cs

View check run for this annotation

Codecov / codecov/patch

Ical.Net/Evaluation/RecurrencePatternEvaluator.cs#L416

Added line #L416 was not covered by tests

// Determine our current week number
var currWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);
while (currWeekNo > weekNo)
{
// If currWeekNo > weekNo, then we're likely at the start of a year
// where currWeekNo could be 52 or 53. If we simply step ahead 7 days
// we should be back to week 1, where we can easily make the calculation
// to move to weekNo.
date = date.AddDays(7);
currWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);
}

// Move ahead to the correct week of the year
date = date.AddDays((weekNo - currWeekNo) * 7);

// Step backward single days until we're at the correct DayOfWeek
while (date.DayOfWeek != pattern.FirstDayOfWeek)
// Ignore the week if it doesn't belong to the current year.
if (Calendar.GetIso8601YearOfWeek(date, pattern.FirstDayOfWeek) == t.Year)
{
date = date.AddDays(-1);
}
// Step backward single days until we're at the correct DayOfWeek
while (date.DayOfWeek != pattern.FirstDayOfWeek)
{
date = date.AddDays(-1);
}

for (var k = 0; k < 7; k++)
{
weekNoDates.Add(date);
date = date.AddDays(1);
for (var k = 0; k < 7; k++)
{
weekNoDates.Add(date);
date = date.AddDays(1);
}
}
}
}

return weekNoDates;
}

Expand Down
Loading