Package: recurring-ical-events
ICal has some complexity to it:
Events, TODOs and Journal entries can be repeated, removed from the feed and edited later on.
This tool takes care of these circumstances.Let’s put our expertise together and build a tool that can solve this!day light saving time (DONE)recurring events (DONE)recurring events with edits (DONE)recurring events where events are omitted (DONE)recurring events events where the edit took place later (DONE)normal events (DONE)recurrence of dates but not hours, minutes, and smaller (DONE)endless recurrence (DONE)ending recurrence (DONE)events with start date and no end date (DONE)events with start as date and start as datetime (DONE)RRULE(DONE)RDATE(DONE)DURATION(DONE)EXDATE(DONE)X-WR-TIMEZONEcompatibilty (DONE)Not included:EXRULE (deprecated), see8.3.2.  Properties RegistryInstallationpipinstallrecurring-ical-eventsSupportSupport using GitHub SponsorsFund specific issues using PolarSupport using Open CollectiveSupport using thanks.devWe accept donations to sustain our work, once or regular.
Consider donating money to open-source as everyone benefits.Exampleimporticalendarimportrecurring_ical_eventsimporturllib.requeststart_date=(2019,3,5)end_date=(2019,4,1)url="http://tinyurl.com/y24m3r8f"ical_string=urllib.request.urlopen(url).read()calendar=icalendar.Calendar.from_ical(ical_string)events=recurring_ical_events.of(calendar).between(start_date,end_date)foreventinevents:start=event["DTSTART"].dtduration=event["DTEND"].dt-event["DTSTART"].dtprint("start{}duration{}".format(start,duration))Output:start 2019-03-18 04:00:00+01:00 duration 1:00:00
start 2019-03-20 04:00:00+01:00 duration 1:00:00
start 2019-03-19 04:00:00+01:00 duration 1:00:00
start 2019-03-07 02:00:00+01:00 duration 1:00:00
start 2019-03-08 01:00:00+01:00 duration 2:00:00
start 2019-03-09 03:00:00+01:00 duration 0:30:00
start 2019-03-10 duration 1 day, 0:00:00UsageTheicalendarmodule is responsible for parsing and converting calendars.
Therecurring_ical_eventsmodule uses such acalendarand creates all repetitions of its events within a time span.To import this module, writeimportrecurring_ical_eventsThere are several methods you can use to unfold repeating events, such asat(a_time)andbetween(a_start, an_end).at(a_date)You can get all events which take place ata_date.
A date can be a year, e.g.2023, a month of a year e.g. January in 2023(2023, 1), a day of a certain month e.g.(2023, 1, 1), an hour e.g.(2023, 1, 1, 0), a minute e.g.(2023, 1, 1, 0, 0), or second as well as adatetime.dateobject anddatetime.datetime.The start and end are inclusive. As an example: if an event is longer than one day it is still included if it takes place ata_date.a_date=2023# a yeara_date=(2023,)# a yeara_date=(2023,1)# January in 2023a_date=(2023,1,1)# the 1st of January in 2023a_date="20230101"# the 1st of January in 2023a_date=(2023,1,1,0)# the first hour of the year 2023a_date=(2023,1,1,0,0)# the first minute in 2023a_date=datetime.date(2023)# the first day in 2023a_date=datetime.date(2023,1,1)# the first day in 2023a_date=datetime.datetime.now()# this exact secondevents=recurring_ical_events.of(an_icalendar_object).at(a_date)The resultingeventsare a list oficalendar events, see below.between(start, end)between(start, end)returns all events happening between a start and an end time. Both arguments can bedatetime.datetime,datetime.date, tuples of numbers passed as arguments todatetime.datetimeor strings in the form of%Y%m%d(yyyymmdd) and%Y%m%dT%H%M%SZ(yyyymmddThhmmssZ).
For examples, seeat(a_date)above.events=recurring_ical_events.of(an_icalendar_object).between(start,end)The resultingeventsare in a list oficalendar events, see below.eventsas listThe result of bothbetween(start, end)andat(a_date)is a list oficalendar events.
By default, all attributes of the event with repetitions are copied, likeUIDandSUMMARY.
However, these attributes may differ from the source event:DTSTARTwhich is the start of the event instance. (always present)DTENDwhich is the end of the event instance. (always present)RDATE,EXDATE,RRULEare the rules to create event repetitions.
They arenotincluded in repeated events, seeIssue 23.
To change this, useof(calendar, keep_recurrence_attributes=True).Different Components, not just EventsBy default therecurring_ical_eventsonly selects events as the name already implies.
However, there are differentcomponentsavailable in acalendar.
You can select which components you like to have returned by passingcomponentsto theoffunction:of(a_calendar,components=["VEVENT"])Here is a template code for choosing the supported types of components:events=recurring_ical_events.of(calendar).between(...)journals=recurring_ical_events.of(calendar,components=["VJOURNAL"]).between(...)todos=recurring_ical_events.of(calendar,components=["VTODO"]).between(...)all=recurring_ical_events.of(calendar,components=["VTODO","VEVENT","VJOURNAL"]).between(...)If a type of component is not listed here, it can be added.
Please create an issue for this in the source code repository.SpeedIf you usebetween()orat()several times, it is faster to re-use the object coming fromof().rcalendar=recurring_ical_events.of(an_icalendar_object)events_of_day_1=rcalendar.at(day_1)events_of_day_2=rcalendar.at(day_2)events_of_day_3=rcalendar.at(day_3)# ...Version FixingIf you use this library in your code, you may want to make sure that
updates can be received but they do not break your code.
The version numbers are handeled this way:a.b.cexample:0.1.12cis changed for each minor bug fix.bis changed whenever new features are added.ais changed when the interface or major assumptions change that may break your code.So, I recommend to version-fix this library to stay with the sameawhilebandccan change.DevelopmentTo run the tests, we usetox.toxtests all different Python versions which we want to  be compatible to.pip3installtoxTo run all the tests:toxTo run the tests in a specific Python version:tox-epy39TestingThis project’s development is driven by tests.
Tests assure a consistent interface and less knowledge lost over time.
If you like to change the code, tests help that nothing breaks in the future.
They are required in that sense.
Example code and ics files can be transferred into tests and speed up fixing bugs.You can view the tests in thetest folder.
If you have a calendar ICS file for which this library does not
generate the desired output, you can add it to thetest/calendarsfolder and write tests for what you expect.
If you like,open an issuefirst, e.g. to discuss the changes and
how to go about it.New ReleasesTo release new versions,edit the Changelog Sectionedit setup.py, the__version__variablecreate a commit and push itwait forGitHub Actionsto finish the buildrunpython3setup.pytag_and_deploynotify the issues about their releaseChangelogv2.1.2Fix RRULE with EXDATE as DATE, seePR 121by Jan Grasnick andPR 122.v2.1.1Claim and test support for Python 3.11.Support deleting events by setting RRULE UNTIL < DTSTART, seeIssue 117.v2.1.0Added support for PERIOD values in RDATE. SeeIssue 113.Fixedicalendar>=5.0.9to supportRDATEof typePERIODwith a time zone.Fixedpytz>=2023.3to assure compatibility.v2.0.2Fixed omitting last event ofRRULEwithUNTILwhen usingpytz, the event starting in winter time and ending in summer time. SeeIssue 107.v2.0.1Fixed crasher with duplicate RRULE. SeePull Request 104v2.0.0bOnly returnVEVENTby default. Addof(...,components=...)parameter to select which kinds of components should be returned. SeeIssue 101.Removebetaindicator. This library works okay: Feature requests come in, not so much bug reports.v1.1.0bAdd repeated TODOs and Journals. SeePull Request 100andIssue 97.v1.0.3bRemove syntax anomalies in README.Switch to GitHub actions because GitLab decided to remove support.v1.0.2bAdd support forX-WR-TIMEZONEcalendars which contain events without an explicit time zone, seeIssue 86.v1.0.1bAdd support forzoneinfo.ZoneInfotime zones, seeIssue 57.Migrate from Travis CI to Gitlab CI.Add code coverage on Gitlab.v1.0.0bRemove Python 2 support, seeIssue 64.Remove support for Python 3.5 and 3.6.Note: These deprecated Python versions may still work. We just do not claim they do.X-WR-TIMEZONEsupport, seeIssue 71.v0.2.4bEvents with a duration of 0 seconds are correctly returned.between()andat()take the same kind of arguments. These arguments are documented.v0.2.3bbetween()andat()allow arguments with time zones now when calendar events do not have time zones, reported inIssue 61andIssue 52.v0.2.2bCheck thatat()does not return an event starting at the next day, seeIssue 44.v0.2.1bCheck that recurring events are removed if they are modified to leave the requested time span, seeIssue 62.v0.2.0bAdd ability to keep the recurrence attributes (RRULE, RDATE, EXDATE) on the event copies instead of stripping them. SeePull Request 54.v0.1.21bFix issue with repetitions over DST boundary. SeeIssue 48.v0.1.20bFix handling of modified recurrences with lower sequence number than their base eventPull Request 45v0.1.19bBenchmark using@mrx23dot’s script and speed up recurrence calculation by factor 4, seeIssue 42.v0.1.18bHandleIssue 28so that EXDATEs match as expected.HandleIssue 27so that parsing some rrule UNTIL values does not crash.v0.1.17bHandleIssue 28where passed arguments lead to errors where it is expected to work.v0.1.16bEvents with an empty RRULE are handled like events without an RRULE.Remove fixed dependency versions, seeIssue 14v0.1.15bRepeated events also include subcomponents.Issue 6v0.1.14bFix compatibilityissue 20: EXDATEs of different time zones are now supported.v0.1.13bRemove attributes RDATE, EXDATE, RRULE from repeated eventsIssue 23Use vDDDTypes instead of explicit date/datetime typePull Request 19Start ChangelogLibraries Usedpython-dateutil- to compute the recurrences of events usingrruleicalendar- the library used to parse ICS filespytz- for timezonesx-wr-timezonefor handling the non-standardX-WR-TIMEZONEproperty.Related Projectsicalevents- another library for roughly the same use-caseOpen Web Calendar- a web calendar to embed into websites which uses this libraryicspy- to create your own calendar eventsMediaNicco Kunzmann talked about this library at the
FOSSASIA 2022 Summit:ResearchRFC 5545RFC 7986– an update to RFC 5545. It does not change any properties useful for scheduling events.Stackoverflow question this is created forhttps://github.com/oberron/annumhttps://stackoverflow.com/questions/28829261/python-ical-get-events-for-a-day-including-recurring-ones#28829401https://stackoverflow.com/questions/20268204/ical-get-date-from-recurring-event-by-rrule-and-dtstarthttps://github.com/collective/icalendar/issues/162https://stackoverflow.com/questions/46471852/ical-parsing-reoccuring-events-in-pythonRDATEhttps://stackoverflow.com/a/46709850/1320237https://tools.ietf.org/html/rfc5545#section-3.8.5.2