icalendar / icalendar

icalendar.rb main repository

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Standard/Daylight parsing is very slow if start is far in the past

justinhoward opened this issue · comments

I'm parsing a calendar from Office 365 with the following:

BEGIN:VCALENDAR
METHOD:PUBLISH
PRODID:Microsoft Exchange Server 2010
VERSION:2.0
BEGIN:VTIMEZONE
TZID:Pacific Standard Time
BEGIN:STANDARD
DTSTART:16010101T020000
TZOFFSETFROM:-0700
TZOFFSETTO:-0800
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010101T020000
TZOFFSETFROM:-0800
TZOFFSETTO:-0700
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3
END:DAYLIGHT
END:VTIMEZONE

The DTSTART properties are set very far in the past. This causes IceCube::Schedule.previous_occurrence to take a very long time (several seconds per event).

[schedule.previous_occurrence(local.to_time), std]

For a calendar with many events, parsing a whole calendar can take minutes.

One solution I've considered is to cache the enumerated occurrences. Another solution might be to look at RRULE and manually adjust the start date to be a single occurrence in the past (for example subtract 1 year from local).

Of the two solutions, I think I prefer the latter, because it should require less computation time. I experimented with that solution and it seems to work well and also reduces the parse time of my test from about 30s to 200ms.

I'm happy to submit a PR if that sounds like a good solution.

I just realized that it gets more complicated if there are multiple RRULE values or if there are RDATE values. It might be better to go with the cache approach. Caching could be tricky since we're working with an infinite series, but we could cache a "window" of time and only increase it if necessary. It needs more thought.

Of course, another solution in my case is to just modify dtstart before parsing, but if it can be fixed upstream, I'd prefer that.

Closing this in favor of #214.