iCalendar Hacking (HPR Show 1286)

Creating iCalendar rules by hand and with a Perl script

Dave Morriss

Table of Contents

Editor’s Note 2020-01-02

The notes for this episode have been reformatted, particularly the long-form notes. This was done to make them more readable. Also, the original Git repository has been changed from Gitorious to GitLab.

In 2019 an iCalendar file was placed on the HPR server at http://hackerpublicradio.org/HPR_Community_News_schedule.ics which you can use in your own calendar application. The file contains the recording times of 12 months of Community News shows and is updated monthly.

The Problem

Back in 2012 Ken Fallon tried to use Google Calendar to set up an event for the recording of the monthly Community News shows on HPR. He wanted to set these on the Saturday before the first Monday of the month. Surprisingly he didn’t find a way to do this and ended up deleting the attempt.

I looked at the calendaring application I use: Thunderbird with the Lightning calendar plugin, to see if I could manage it. I also couldn’t find a way.

This episode documents my journey to find a way to make the calendar entries we need.


I was aware that calendars like Google Calendar and many more use iCalendar to represent and communicate events, and so I thought I would try and find out more. I have often wondered how iCalendar calendaring works, so I grabbed a copy of RFC 5545 and absorbed enough to get a vague idea of how it defines recurrent entries. If you’d like to read this yourself have a look at http://www.ietf.org/rfc/rfc5545.txt

There are two primary methods of defining recurrent events within iCalendar: RRULE and RDATE. The RRULE property is the more powerful of the two and the more complex. The description of RRULE is long and involved, but in the context of this problem I could see how to define the first Monday of every month:

  • FREQ=MONTHLY simply means the rule repeats every month.
  • BYDAY=1MO then means that every month the first Monday is selected.

Most calendar applications are well able to deal with this sort of specification, and it seems to be the way in which most recurrent events are defined.

Experiment 1

However, this is not what we want. We need the Saturday before the first Monday, but the iCalendar syntax doesn’t have any obvious way of subtracting 2 days to get the Saturday before, especially when it could be in the previous month.

The definition of the BYDAY rule part specifies a comma separated list of days of the week (MO, TU, WE, TH, FR, SA, SU). As we have seen these weekday specifications can also be preceded by a digit as in 1MO.

There is also a rule part BYSETPOS which modifies the BYDAY rule part. It is followed by a comma separated list of values which corresponds to the nth occurrence within the set of events specified by the rule.

This led me to believe that I could make a rule as follows:

  • FREQ=MONTHLY as before means the rule repeats every month.
  • BYDAY=SA,SU,1MO then means that every month the weekend before the first Monday is selected.
  • BYSETPOS=1 means to select the first first day of the group, the Saturday

I was rather surprised to find that this actually worked, but soon discovered that it has a fatal flaw. If the three days in BYDAY are all in the same month it works fine, but if either the Saturday or Sunday are in the previous month it can’t backtrack far enough and drops the event on the wrong day.

Even if this worked, I suspect many calendar applications couldn’t define it anyway. Thunderbird+Lightning cannot for certain. The user interface is just not able to specify this amount of detail.

The following is the full iCalendar entry that I plugged into Thunderbird:

LOCATION:mumble.openspeak.cc port: 64747
SUMMARY:HPR Community News

Experiment 2

However, I discovered there is an alternative way through the RDATE specification. With it you can define a number of events by pre-computing them. I was able to build a test calendar containing the next twelve Community News events (there’s naturally a plug-in for Vim which recognises the syntax!), load it into Thunderbird and make it send out invitations.

In true Hacker style I wrote a Perl script1 to generate the necessary RDATE dates. The script uses the Perl module Date::Calc to perform date calculations and Data::ICal to generate iCalendar data.

Running the script in the following way:

./make_meeting > experiment2.ics

generates a file containing 12 appointments that can be loaded into Thunderbird (and presumably any other iCalendar-based calendar).

PRODID:Data::ICal 0.20
X-WR-CALNAME:Hacker Public Radio
DESCRIPTION:This is a test\, building an iCalendar file and loading it into
  Thunderbird.\n-----------------------------------------\nMumble settings\
 nServer Name: Anything you like\nServer Address: mumble.openspeak.cc \nPor
 t: 64747\nName: Your name or alias is fine\n\nDon't have mumble\, setup in
 structions can be found on our wiki -\nhttp://linuxbasix.com/tiki-index.ph
LOCATION:mumble.openspeak.cc port: 64747
SUMMARY:HPR Community News

Thunderbird’s event dialog will not let you edit the sub-events, just delete them, but the idea works, albeit in a rather clunky way.

I don’t have access to many other calendaring systems, except for Korganizer. It sees the multiple dates as multiple discrete events rather than a single recurring event.

Experiment 3

Other calendaring systems that do not use iCalendar can handle this problem more effectively. For many years I have used a tool called pcal (http://pcal.sourceforge.net/) that generates PostScript calendars which I print and hang on the wall. It can reliably specify the Saturday before the first Monday of each month with the expression:

Saturday before first Monday in all    HPR Community News (19:00 - 21:00)

Another tool which can do this is Remind (http://www.roaringpenguin.com/products/remind, http://www.linuxjournal.com/article/3529). With this the following expression achieves the required result:

REM Mon 1 --2 AT 19:00 MSG HPR Community News (19:00 - 21:00)

Remind comes with a tool which can generate iCalendar data, called rem2ics. It expects output from the remind command from which it generates data. The following example generates 12 meetings from the above reminder which is in the file .reminders.

remind -s12 .reminders | TZ=UTC rem2ics -do >reminders.ics

The result uses the RDATE specification as discussed in Experiment 2, with the same result.

PRODID:http://mark.atwood.name/code/rem2ics rem2ics 0.93
SUMMARY:HPR Community News (19\:00 - 21\:00)
COMMENT: generated by rem2ics 0.93\n http://mark.atwood.name/code/rem2ic
 s\n data[1]=|2012/11/03 * * * 1140 7\:00pm HPR Community News (19\:00 -


It seems that the iCalendar specification should be able to generate the appointments we need using the compact RRULE specification. However, in the (admittedly small) sample of calendaring applications checked this does not seem to have been implemented properly.

Other tools that do not use iCalendar have less difficulty representing such events but are not as widely adopted.

If anyone has any ideas about how this problem could be solved more effectively then please let me know!

  1. Note, this is a viewable HTML version of the script, but a downloadable version exists in a Git repository. See the Links section for details.