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
9 changes: 4 additions & 5 deletions Ical.Net.Tests/contrib/libical/icalrecur_test.out
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,10 @@ START-AT:20210302T100000
INSTANCES:20210302T102000,20210302T112000,20210302T122000,20210302T132000,20210302T142000,20210302T152000,20210302T162000,20210302T172000,20210302T182000,20210302T192000,20210302T202000,20210302T212000,20210302T222000,20210302T232000
PREV-INSTANCES:20210302T092000,20210302T082000,20210302T072000,20210302T062000,20210302T052000,20210302T042000,20210302T032000,20210302T022000,20210302T012000,20210302T002000,20210301T232000,20210301T222000,20210301T212000,20210301T202000,20210301T192000,20210301T182000,20210301T172000,20210301T162000,20210301T152000,20210301T142000

# TODO: FIX (see https://github.com/ical-org/ical.net/issues/618)
# RRULE:FREQ=YEARLY;BYWEEKNO=6;BYDAY=TU;WKST=TH;UNTIL=20210612T000000Z
# DTSTART:20180206T080001
# INSTANCES:20180213T080001,20190212T080001,20200211T080001,20210209T080001
# PREV-INSTANCES:20210209T080001,20200211T080001,20190212T080001,20180213T080001
RRULE:FREQ=YEARLY;BYWEEKNO=6;BYDAY=TU;WKST=TH;UNTIL=20210612T000000Z
DTSTART:20180213T080001
INSTANCES:20180213T080001,20190212T080001,20200211T080001,20210209T080001
PREV-INSTANCES:20210209T080001,20200211T080001,20190212T080001,20180213T080001

RRULE:FREQ=DAILY;BYMINUTE=1,2,3,4;INTERVAL=2;COUNT=3
DTSTART:20241018
Expand Down
38 changes: 25 additions & 13 deletions Ical.Net/CalendarExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,32 @@ namespace Ical.Net;
public static class CalendarExtensions
{
/// <summary>
/// https://blogs.msdn.microsoft.com/shawnste/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net/
/// Calculate the week number according to ISO.8601, as required by RFC 5545.
/// </summary>
public static int GetIso8601WeekOfYear(this System.Globalization.Calendar calendar, DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
public static int GetIso8601WeekOfYear(this System.Globalization.Calendar calendar, DateTime time, DayOfWeek firstDayOfWeek)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
var day = calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// A week is defined as a
// seven day period, starting on the day of the week defined to be
// the week start(see WKST). Week number one of the calendar year
// is the first week that contains at least four (4) days in that
// calendar year.

// Return the week of our adjusted day
return calendar.GetWeekOfYear(time, rule, firstDayOfWeek);
// We add 3 to make sure the test date is in the 'right' year, because
// otherwise we might end up with week 53 in a year that only has 52.
var tTest = GetStartOfWeek(time, firstDayOfWeek).AddDays(3);
var res = calendar.GetWeekOfYear(tTest, CalendarWeekRule.FirstFourDayWeek, firstDayOfWeek);

return res;
}

/// <summary>
/// Calculate and return the date that represents the first day of the week the given date is
/// in, according to the week numbering required by RFC 5545.
/// </summary>
private static DateTime GetStartOfWeek(this DateTime t, DayOfWeek firstDayOfWeek)
{
var t0 = ((int) firstDayOfWeek) % 7;
var tn = ((int) t.DayOfWeek) % 7;
return t.AddDays(-((tn + 7 - t0) % 7));
}
}
}
15 changes: 7 additions & 8 deletions Ical.Net/Evaluation/RecurrencePatternEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Ical.Net.DataTypes;
using Ical.Net.Utility;
Expand Down Expand Up @@ -400,15 +399,15 @@ private List<DateTime> GetWeekNoVariants(List<DateTime> dates, RecurrencePattern
{
var date = t;
// Determine our current week number
var currWeekNo = Calendar.GetIso8601WeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
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, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
currWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);
}

// Move ahead to the correct week of the year
Expand Down Expand Up @@ -629,7 +628,7 @@ private List<DateTime> GetAbsWeekDays(DateTime date, WeekDay weekDay, Recurrence
}
else if (pattern.Frequency == FrequencyType.Weekly || pattern.ByWeekNo.Count > 0)
{
var weekNo = Calendar.GetIso8601WeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
var weekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);

// Go to the first day of the week
date = date.AddDays(-GetWeekDayOffset(date, pattern.FirstDayOfWeek));
Expand All @@ -640,8 +639,8 @@ private List<DateTime> GetAbsWeekDays(DateTime date, WeekDay weekDay, Recurrence
date = date.AddDays(1);
}

var nextWeekNo = Calendar.GetIso8601WeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
var currentWeekNo = Calendar.GetIso8601WeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
var nextWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);
var currentWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);

//When we manage weekly recurring pattern and we have boundary case:
//Weekdays: Dec 31, Jan 1, Feb 1, Mar 1, Apr 1, May 1, June 1, Dec 31 - It's the 53th week of the year, but all another are 1st week number.
Expand All @@ -655,7 +654,7 @@ private List<DateTime> GetAbsWeekDays(DateTime date, WeekDay weekDay, Recurrence
}

date = date.AddDays(7);
currentWeekNo = Calendar.GetIso8601WeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
currentWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);
}
}
else if (pattern.Frequency == FrequencyType.Monthly || pattern.ByMonth.Count > 0)
Expand All @@ -671,7 +670,7 @@ private List<DateTime> GetAbsWeekDays(DateTime date, WeekDay weekDay, Recurrence

while (date.Month == month)
{
var currentWeekNo = Calendar.GetIso8601WeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, pattern.FirstDayOfWeek);
var currentWeekNo = Calendar.GetIso8601WeekOfYear(date, pattern.FirstDayOfWeek);

if ((pattern.ByWeekNo.Count == 0 || pattern.ByWeekNo.Contains(currentWeekNo))
&& (pattern.ByMonth.Count == 0 || pattern.ByMonth.Contains(date.Month)))
Expand Down
Loading