-
Notifications
You must be signed in to change notification settings - Fork 248
Description
Describe the bug
Preview version is returning incorrect occurrences under certain circumstances compared to both expectations and the previous version. This seems to be w/r/t to combining:
FREQ=DAILYwithBYMONTHDAY, (which should be allowable)- previously returned an empty set which may have been incorrect also
- now returns every day except for the day actually listed under
BYMONTHDAY
FREQ=MONTHLYwithBYYEARDAY(which is invalid per spec)- behaves as if it's just "monthly"
- had same behavior in v4 which I believe is incorrect
FREQ=DAILYwithBYYEARDAY(which is invalid per spec)- behaves as if it's just "daily"
- had same behavior in v4 which I believe is incorrect
To Reproduce
Steps to reproduce the behavior:
Here's an example of combining DAILY with BYMONTHDAY that previously returned an empty set. This would be the equivalent of:
DTSTART:20250201T000000Z
RRULE:FREQ=DAILY;BYMONTHDAY=20
var evt = new CalendarEvent
{
Start = new CalDateTime(new DateOnly(2025, 2, 1)),
RecurrenceRules =
[
new RecurrencePattern("FREQ=DAILY;BYMONTHDAY=20")
]
};
var r = evt.GetOccurrences(
new DateTime(2025, 2, 1, 0, 0, 0, DateTimeKind.Utc), // 2025-02-01
new DateTime(2025, 2, 3, 0, 0, 0, DateTimeKind.Utc) // 2025-02-02
).ToList();
// At the very least this should return EMPTY like v4
// but instead it returns 2025-02-01 and 2025-02-02 which are _not_ monthday=20
Assert.Empty(r);
var r2 = evt.GetOccurrences(
new DateTime(2025, 2, 19, 0, 0, 0, DateTimeKind.Utc), // 2025-02-19
new DateTime(2025, 2, 22, 0, 0, 0, DateTimeKind.Utc) // 2025-02-22
).ToList();
// IIF anything, I'd expect this to be Day 20 (from the rule) but instead its day 19 and 21 (everything except 20!)
var single = Assert.Single(r);
Assert.Equal(20, r[0].Period.StartTime.Date.Day); Here's an example of combining MONTHLY with BYYEARDAY that previously returned an empty set
DTSTART:20250101T000000Z
RRULE:FREQ=MONTHLY;BYYEARDAY=20
var evt = new CalendarEvent
{
Start = new CalDateTime(new DateOnly(2025, 1, 1)),
RecurrenceRules =
[
new RecurrencePattern("FREQ=MONTHLY;BYYEARDAY=20")
]
};
var r = evt.GetOccurrences(
new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), // 2025-01-01
new DateTime(2025, 1, 2, 0, 0, 0, DateTimeKind.Utc) // 2025-01-02
).ToList();
// At the very least this should return EMPTY but instead it returns 2025-01-01 which is not yearday=20
Assert.Empty(r);
var r2 = evt.GetOccurrences(
new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), // 2025-01-01
new DateTime(2025, 2, 2, 0, 0, 0, DateTimeKind.Utc) // 2025-02-02
).ToList();
// IIF this were valid per the spec, I'd expect this to be Day 20 (from the rule)
// v4 and v5 returns the first day of each month instead
var single = Assert.Single(r);
Assert.Equal(20, r[0].Period.StartTime.Date.Day); Expected behavior
These both should probably return an empty set similar to version 4. However certain online rule engines treat them as valid and will produce the 20th in every month for the first rule, and January 20 every year for the second. You can try them here and here.
The specification indicates that BYMONTHDAY is only invalid if FREQ=WEEKLY and that BYYEARDAY is only invalid
The BYMONTHDAY rule part MUST NOT be specified when the FREQ rule part is set to WEEKLY.
which makes me think that the empty set behavior was possibly a bug in v4. In any case iif it's going to return values, it should not return 2025-02-01 as the first instance and it most certainly should not be excluding 2025-02-20!!
Conversely, the specification indicates that BYYEARDAY cannot be specified with daily/weekly/monthly:
The BYYEARDAY rule part MUST NOT be specified when the FREQ rule part is set to DAILY, WEEKLY, or MONTHLY.
Which means that the second event about really should be an empty set; it most certainly shouldn't return every single day
Environment (please complete the following information):
- OS: Win11
- .NET version: .NET9
- ical.net version:
5.0.0-pre.39