u01jmg3 / ics-parser

Parser for iCalendar Events • PHP 8+, 7 (≥ 7.4), 5 (≥ 5.6)
MIT License
450 stars 144 forks source link

Handle MONTHLY rrules with BYDAY set as the [-]5th instance of a weekday #326

Closed s0600204 closed 1 year ago

s0600204 commented 1 year ago

As reported in #324, requesting the 5th (or -5th) Monday/Tuesday/whatever of a month was returning erroneous dates caused by overlapping into the next (or previous) month.

There was also a related edge case, where the very last occurrence sometimes wasn't being generated. Consider the following input:

DTSTART:20200103
RRULE:FREQ=MONTHLY;BYDAY=-5FR;UNTIL=20200502

The last date generated should be the 1st of May, however running this with the parser (with the patch from #324), this date is not output.

The code essentially does this (pseudo):

$until = {RRULE UNTIL};
$currentdate = {DTSTART};

while ($currentdate <= $until) {
    generate_occurrences();
    if (any occurrences <= $until)
        add_occurrence_to_output();
    $currentdate += 1 month;
}

After transitioning from April 3rd to May 3rd, we find that as 3rd May ($currentdate) is after the 2nd May ($until) the loop exits, without generating any May occurrences for consideration.

The solution given in this PR is to use a new $untilWhile variable that is one $frequencyInterval (in this case one month) later along than $until, and use that in the while loop conditional statement. (Whilst still using $until to check each individual candidate occurrence.)


Initial fix provided by @room34

Fixes #324