Skip to content

Commit 135370f

Browse files
authored
Fix weekly bymonth (#880)
Weekly rules that include BYMONTH were only including weeks that start inside the given months. This fix checks the end of the week also to see if any part of the week is inside the given months. The date will not always be the start of a week, since the reference date is first, but extra months are filtered out later. Fixes #879
1 parent 9357044 commit 135370f

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

Ical.Net.Tests/RecurrenceTests_From_Issues.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Linq;
1111
using Ical.Net.CalendarComponents;
1212
using Ical.Net.DataTypes;
13+
using Ical.Net.Evaluation;
1314
using NUnit.Framework;
1415

1516
namespace Ical.Net.Tests;
@@ -513,4 +514,21 @@ public void Except_Tuesday_Thursday_Saturday_Sunday()
513514
}
514515
});
515516
}
517+
518+
[Test]
519+
public void Weekly_ByDay_ByMonth()
520+
{
521+
// Bug #879
522+
523+
var rp = new RecurrencePattern("FREQ=WEEKLY;BYDAY=SU,MO,TU,WE,TH,FR;BYMONTH=5,6,7,8,9");
524+
var rpe = new RecurrencePatternEvaluator(rp);
525+
526+
var referenceDate = new CalDateTime(2025, 11, 07, 0, 0, 0, "Central Standard Time");
527+
var recurringPeriods = rpe.Evaluate(referenceDate, null, null);
528+
529+
var result = recurringPeriods.FirstOrDefault()?.StartTime;
530+
531+
var expected = new CalDateTime(2026, 05, 01, 0, 0, 0, "Central Standard Time");
532+
Assert.That(result, Is.EqualTo(expected));
533+
}
516534
}

Ical.Net/Evaluation/RecurrencePatternEvaluator.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,18 @@ private static IEnumerable<CalDateTime> GetMonthVariants(IEnumerable<CalDateTime
308308
}
309309

310310
// Limit behavior
311-
return dates.Where(date => pattern.ByMonth.Contains(date.Month));
311+
if (pattern.Frequency == FrequencyType.Weekly)
312+
{
313+
// The dates here represent weeks, with each date being the
314+
// start of a week except for the initial reference date.
315+
// Return weeks that have any day within BYMONTH.
316+
return dates.Where(date => pattern.ByMonth.Contains(date.Month)
317+
|| pattern.ByMonth.Contains(date.AddDays(6).Month));
318+
}
319+
else
320+
{
321+
return dates.Where(date => pattern.ByMonth.Contains(date.Month));
322+
}
312323
}
313324

314325
/// <summary>

0 commit comments

Comments
 (0)