u01jmg3 / ics-parser

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

Possible Recurrence Rule Processing Bug: Event Appears in Parser that Does Not Exist #293

Closed EnigmaSolved closed 2 years ago

EnigmaSolved commented 2 years ago

Greetings, thank you so much for creating ics-parser -- it has been super-useful!

I may have encountered a bug (or I may be just misunderstanding something). I have an event (we'll call it "Example" though the real name is different) that repeats at 9am every 4 weeks on a Tuesday. On Monday, January 10 I edited the event to end its repetition (so that it would no longer recur and would not recur for Tuesday, January 11, the next normal recurrence). And I created a new version of the event 4 weeks out on Tuesday, February 8. Thus I was skipping Tuesday, January 11. However, somehow the ics-parser is reading that the Tuesday January 11 event still exists/occurs (ie, the ics-parser is producing an instance of this event for Tuesday, January 11), which makes me think that something is being misinterpreted with the recurrence rules (perhaps?). Below is a subset of the actual ics file. New Lines are added for visual clarity. I've omitted all other events, and I have changed the Event Summaries and Categories, but everything else is unchanged.

Everything else has been working fine for a few weeks (ie, I get valid events via the ics-parser and everything else works fine with my code and with ics-parser), so there seems to be something peculiar about this event.

Let me know if you need anything else for debugging, or if I've just made some silly mistake somewhere!

Thanks much, and if this is a bug I hope the above is helpful info! :)

ICS Data (a subset of what is created automatically by Microsoft Outlook):

BEGIN:VCALENDAR
PRODID:-//Microsoft Corporation//Outlook 16.0 MIMEDIR//EN
VERSION:2.0
METHOD:PUBLISH
X-CALSTART:20211213T021500Z
X-CALEND:20220313T030000Z
X-CLIPSTART:20211212T050000Z
X-CLIPEND:20220313T050000Z
X-WR-RELCALID:{00000018-D1A5-252E-E2C9-5B3689335C4C}
X-WR-CALNAME:My Calendar
X-PUBLISHED-TTL:PT60M
X-MS-OLK-WKHRSTART;TZID="Eastern Standard Time":083000
X-MS-OLK-WKHREND;TZID="Eastern Standard Time":193000
X-MS-OLK-WKHRDAYS:MO,TU,WE,TH,FR
BEGIN:VTIMEZONE
TZID:Eastern Standard Time
BEGIN:STANDARD
DTSTART:16011104T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=11
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010311T020000
RRULE:FREQ=YEARLY;BYDAY=2SU;BYMONTH=3
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
END:VTIMEZONE

BEGIN:VEVENT
CATEGORIES:Example-Category
CLASS:PUBLIC
CREATED:20210827T190446Z
DTEND;TZID="Eastern Standard Time":20211214T100000
DTSTAMP:20220111T132442Z
DTSTART;TZID="Eastern Standard Time":20211214T090000
LAST-MODIFIED:20220110T182246Z
LOCATION:Video
PRIORITY:5
RRULE:FREQ=WEEKLY;COUNT=1;INTERVAL=4;BYDAY=TU;WKST=SU
SEQUENCE:0
SUMMARY;LANGUAGE=en-us:Example
TRANSP:OPAQUE
UID:040000008200E00074C5B7101A82E008000000002038CCDF549BD701000000000000000
    01000000078D2D3EC1A3002468F1B2080CD87C588
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
X-MICROSOFT-CDO-IMPORTANCE:1
X-MICROSOFT-DISALLOW-COUNTER:FALSE
X-MS-OLK-AUTOFILLLOCATION:FALSE
X-MS-OLK-AUTOSTARTCHECK:FALSE
X-MS-OLK-CONFTYPE:0
END:VEVENT

BEGIN:VEVENT
CATEGORIES:Example-Category
CLASS:PUBLIC
CREATED:20220110T182225Z
DTEND;TZID="Eastern Standard Time":20220208T100000
DTSTAMP:20220111T132442Z
DTSTART;TZID="Eastern Standard Time":20220208T090000
LAST-MODIFIED:20220110T182247Z
LOCATION:Video
PRIORITY:5
RRULE:FREQ=WEEKLY;COUNT=2;INTERVAL=4;BYDAY=TU;WKST=SU
SEQUENCE:0
SUMMARY;LANGUAGE=en-us:Example
TRANSP:OPAQUE
UID:040000008200E00074C5B7101A82E008000000006076B81B2506D801000000000000000
    01000000019E99D3DDF9CAB4F8798BD2DD77FC67E
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
X-MICROSOFT-CDO-IMPORTANCE:1
X-MICROSOFT-DISALLOW-COUNTER:FALSE
X-MS-OLK-AUTOFILLLOCATION:FALSE
X-MS-OLK-AUTOSTARTCHECK:FALSE
X-MS-OLK-CONFTYPE:0
END:VEVENT

END:VCALENDAR

A sample of my PHP code:

$daysThroughNextMonthPlus = ( (date('t') - date('j')) + date('t', strtotime('+1 month')) + 2 ); // Includes 2 day fudge-factor for ICal function.
$ical = new ICal\ICal(array(
    'defaultWeekStart'            => 'SU',  
    'disableCharacterReplacement' => true, // Prevents costly character replacements (eg, curly quotes and other special characters).
    'filterDaysAfter'             => $daysThroughNextMonthPlus,
    'filterDaysBefore'            => 2,  // Default value
));
$events = $ical->eventsFromRange( 
    date('Y-m-d'), 
    date('Y-m-d', strtotime('+ ' . $daysThroughNextMonthPlus . ' days')) 
);
if($events){  }
s0600204 commented 2 years ago

Forgive me, I'm curious: @EnigmaSolved, when you say you "edited the event to end its repetition" - was this manually or via MS Outlook's user-interface?

EnigmaSolved commented 2 years ago

Forgive me, I'm curious: @EnigmaSolved, when you say you "edited the event to end its repetition" - was this manually or via MS Outlook's user-interface?

Ah, yes, via MS Outlook's user-interface. Great question @s0600204 -- I should have been more clear! :) In Outlook I went into the recurrence settings and set an end date for the recurrence to be prior to Tuesday, January 11. After realizing that the event was still being picked up by ics-parser as having a recurrence on January 11 I tried setting the end date for even earlier (initially I had set it for January 10), thinking perhaps something about the close proximity might matter somehow, but setting it to earlier (eg, last week? can't remember what exactly I set it to) didn't seem to make any difference.

s0600204 commented 2 years ago

Hmm. Seems there's a couple of behaviour quirks within Outlook:

Anyway, this doesn't solve the problem, which is that COUNT=1 and we don't currently handle this case correctly. Pull Request #294 should provide a workable solution.

And thank you for reporting this.

EnigmaSolved commented 2 years ago

I only have a second, but first wanted to say Thank you @s0600204 ! And then add (which I probably should have clarified) that this ics file is generated by Outlook and so is only a subset of the full Outlook calendar, which is probably why some of the weirdness you mention regarding the first occurrence being so recent (because the generated ics is configured to only include a little bit of history, and mostly just include future events, for obvious reasons).

I also suppose then it is possible that if the timing had been different that we could have a COUNT=2 or COUNT=3 etc. (if I'm interpreting things correctly, and COUNT refers to how many repetitions/recurrences before event ceases to recur).

Again, thank you so much, and I'm glad this has been helpful info in improving the software!