-
Notifications
You must be signed in to change notification settings - Fork 249
Implement BYDAY with offset and limiting behavior
#887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
9a265df
8aceaa4
beea704
7d556e8
ab0dff5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -181,3 +181,94 @@ INSTANCES:20250101,20251231,20260101 | |
| DTSTART:20250601 | ||
| RRULE:FREQ=YEARLY;BYMONTH=6;BYMONTHDAY=2,-2;UNTIL=20250630 | ||
| INSTANCES:20250602,20250629 | ||
|
|
||
| ############################## START ERRATA 1913 TESTS ############################## | ||
| # RFC errata 1913 (https://www.rfc-editor.org/errata_search.php?rfc=1913&eid=1913): | ||
| # 'The numeric value in a BYDAY rule part with the FREQ rule part set to YEARLY corresponds | ||
| # to an offset within the month when the BYMONTH rule part is present, and corresponds to an | ||
| # offset within the year when the BYWEEKNO or BYMONTH rule parts are NOT present.' | ||
| # | ||
| # These 12 tests verify the behavior with the interpretation that | ||
| # * when only BYMONTH is present, the numeric BYDAY offset applies within the month, | ||
| # * when BYWEEKNO is present, the numeric BYDAY offset applies within the week. | ||
| # | ||
| # Disclaimer: Other iCalendar libraries may interpret this differently. | ||
|
|
||
| # Yearly BYMONTH numeric BYDAY (2MO) - 2nd Monday in each BYMONTH | ||
| RRULE:FREQ=YEARLY;BYMONTH=6,9;BYDAY=2MO;COUNT=4 | ||
| DTSTART:20260601T090000 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DTSTART is not in line with the RRULE, which makes the case undefined according to the RFC (similar in other test cases). Unless this test should explicitly cover the undefined case, it would be good to have DTSTART aligned with RRULE, otherwise readers would have to think about whether the deviation is intentional. The time part could be omitted, which would make the test somewhat more concise. |
||
| DURATION:PT1H | ||
|
axunonb marked this conversation as resolved.
Outdated
|
||
| INSTANCES:20260608T090000,20260914T090000,20270614T090000,20270913T090000 | ||
|
|
||
| # Yearly without BYMONTH numeric BYDAY (20MO) - 20th Monday of the YEAR | ||
| RRULE:FREQ=YEARLY;BYDAY=20MO;COUNT=3 | ||
| DTSTART:20260101T090000 | ||
| DURATION:PT1H | ||
| INSTANCES:20260518T090000,20270517T090000,20280515T090000 | ||
|
|
||
| # Yearly BYMONTH negative BYDAY (-1SU) - last Sunday of each BYMONTH | ||
| RRULE:FREQ=YEARLY;BYMONTH=6,9;BYDAY=-1SU;COUNT=2 | ||
| DTSTART:20260601T090000 | ||
| DURATION:PT1H | ||
| INSTANCES:20260628T090000,20260927T090000 | ||
|
|
||
| # Yearly BYMONTH=3 BYDAY=1MO - valid: 1st Monday of March each year | ||
| RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=1MO;UNTIL=20270101T000000Z | ||
| DTSTART:20240101T090000 | ||
| DURATION:PT1H | ||
| START-AT:20240101 | ||
| INSTANCES:20240304T090000,20250303T090000,20260302T090000 | ||
|
|
||
| # Yearly BYMONTH=3 BYDAY=6MO - invalid: 6th Monday in March doesn't exist | ||
| RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=6MO | ||
| DTSTART:20240101T090000 | ||
| DURATION:PT1H | ||
| START-AT:20240101 | ||
| EXCEPTION:Ical.Net.Evaluation.EvaluationOutOfRangeException | ||
| EXCEPTION-STEP:Enumeration | ||
|
|
||
| # Yearly BYWEEKNO=10 BYDAY=1MO - valid: Monday of ISO week 10 each year | ||
| RRULE:FREQ=YEARLY;BYWEEKNO=10;BYDAY=1MO;COUNT=3 | ||
|
axunonb marked this conversation as resolved.
|
||
| DTSTART:20240101T090000 | ||
| DURATION:PT1H | ||
| INSTANCES:20240304T090000,20250303T090000,20260302T090000 | ||
|
|
||
| # Yearly BYWEEKNO=10 BYDAY=2MO - invalid: 2nd Monday in a week doesn't exist -> out of range | ||
| RRULE:FREQ=YEARLY;BYWEEKNO=10;BYDAY=2MO | ||
| DTSTART:20240101T090000 | ||
| DURATION:PT1H | ||
| EXCEPTION:Ical.Net.Evaluation.EvaluationOutOfRangeException | ||
| EXCEPTION-STEP:Enumeration | ||
|
|
||
| # Yearly BYDAY=15MO - 15th Monday of the year | ||
| RRULE:FREQ=YEARLY;BYDAY=15MO;COUNT=3 | ||
|
axunonb marked this conversation as resolved.
Outdated
|
||
| DTSTART:20240101T090000 | ||
| DURATION:PT1H | ||
| INSTANCES:20240408T090000,20250414T090000,20260413T090000 | ||
|
|
||
| # Monthly BYMONTHDAY=13 with BYDAY=MO | ||
| RRULE:FREQ=MONTHLY;BYMONTHDAY=13;BYDAY=MO;UNTIL=20271231T235959Z | ||
| DTSTART:20250913T090000 | ||
| DURATION:PT1H | ||
| START-AT:20251013 | ||
| INSTANCES:20251013T090000,20260413T090000,20260713T090000,20270913T090000,20271213T090000 | ||
|
|
||
| # Yearly BYMONTHDAY=1,8 with BYDAY offsets (expand matrix - note2) | ||
| RRULE:FREQ=YEARLY;BYMONTHDAY=1,8;BYDAY=22MO,23TU,25MO,36TU;UNTIL=20350101T000000 | ||
| DTSTART:20260601 | ||
| DURATION:P1D | ||
| INSTANCES:20260601,20270608,20320608 | ||
|
|
||
| # Monthly BYMONTHDAY=1,8; BYDAY=1MO,2TU - limiting behavior: Monthly by month day with day offsets | ||
| RRULE:FREQ=MONTHLY;BYMONTHDAY=1,8;BYDAY=1MO,2TU;UNTIL=20270101 | ||
| DTSTART:20260601 | ||
| DURATION:P1D | ||
| INSTANCES:20260601,20260908,20261208 | ||
|
|
||
| # Yearly BYMONTH=6-12; BYMONTHDAY=1,8; BYDAY=1MO,2TU - Yearly by month and by month day, with day offsets | ||
| RRULE:FREQ=YEARLY;BYMONTH=6,7,8,9,10,11,12;BYMONTHDAY=1,8;BYDAY=1MO,2TU;UNTIL=20270101 | ||
| DTSTART:20260601 | ||
| DURATION:P1D | ||
| INSTANCES:20260601,20260908,20261208 | ||
|
|
||
| ############################## END ERRATA 1913 TESTS ############################## | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // | ||
| // Copyright ical.net project maintainers and contributors. | ||
| // Licensed under the MIT license. | ||
| // | ||
| #nullable enable | ||
| using System.Linq; | ||
| using Ical.Net.DataTypes; | ||
| using NUnit.Framework; | ||
|
|
||
| namespace Ical.Net.Tests.TestHelpers; | ||
|
|
||
| internal static class OccurrenceTester | ||
| { | ||
| public static void AssertOccurrences( | ||
| Calendar cal, | ||
| CalDateTime? fromDate, | ||
| CalDateTime? toDate, | ||
| Period[] expectedPeriods, | ||
| string[]? timeZones, | ||
| int eventIndex | ||
| ) | ||
| { | ||
| var evt = cal.Events.Skip(eventIndex).First(); | ||
|
|
||
| var occurrences = toDate == null | ||
| ? evt.GetOccurrences(fromDate).ToList() | ||
| : evt.GetOccurrences(fromDate).TakeWhileBefore(toDate).ToList(); | ||
|
|
||
| Assert.Multiple(() => | ||
| { | ||
| Assert.That( | ||
| occurrences, | ||
| Has.Count.EqualTo(expectedPeriods.Length), | ||
| $"There should have been {expectedPeriods.Length} occurrences; there were {occurrences.Count}"); | ||
|
|
||
| if (evt.RecurrenceRules.Count > 0) | ||
| { | ||
| Assert.That(evt.RecurrenceRules, Has.Count.EqualTo(1)); | ||
| } | ||
|
|
||
| for (var i = 0; i < expectedPeriods.Length; i++) | ||
| { | ||
| var period = new Period(expectedPeriods[i].StartTime, expectedPeriods[i].EffectiveDuration!.Value); | ||
|
|
||
| Assert.That(occurrences[i].Period, Is.EqualTo(period), "Event should occur on " + period); | ||
| if (timeZones != null) | ||
| { | ||
| Assert.That(period.StartTime.TimeZoneName, Is.EqualTo(timeZones[i]), | ||
| $"Event {period} should occur in the {timeZones[i]} timezone"); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.