(RFC reading for fun and pragmatism!)
My girlfriend is a nurse, and around these parts that means she works shift work. Her schedule is a block of shifts (sometimes day shifts, sometimes evening shifts) followed by a block of days off (which also varies as to the number of days), and the entire schedule itself repeats every so many weeks. Basically, picture something like this:
While there is a pattern to it, it essentially means that without access to a copy of her schedule readily at hand, it is literally impossible to know if we are free on some random day next month. So obviously, I want an electronic version at the ready for these types of inquiries.
Unfortunately, it is also incredibly tedious to enter all of these shifts one by one, by hand, into something like Google Calendar, because it requires manually creating dozens of events (“repeats every other Monday” unfortunately does not cut it here :P), and on each of them, manually selecting “Repeats,” manually selecting “Custom…”, manually selecting “every X weeks”, all without introducing any errors. Ugh.
Fortunately, here to save the day… the iCalendar specification!
The iCalendar specification (as in RFC 5545, not to be confused with good ol’ iCal, now known as Apple’s Calendar app) is a “data format for representing and exchanging calendaring and scheduling information such as events, to-dos, journal entries, and free/busy information, independent of any particular calendar service or protocol.”
Basically, it’s a list of rules about how to describe events in computer-friendly language, and if you follow those rules, users can import your events consistently in whatever various calendaring programs they might be using. Glancing through the specification, you’ll see it talks about how to specify all kinds of features you may have seen in various calendaring apps, such as:
Specify a location
Specify a time zone
Repeat an event with a certain frequency
Note whether someone’s an optional or required attendee
Denote whether it shows up as busy or free time on someone’s calendar
Send an alert a few minutes before an event happens
...and much, much more.
If you’ve ever received an email with a
.ics file attached, and when you click it you’re prompted to add an event to your calendar, such as below… Congratulations! You officially have experience with iCalendar! :D
Let’s talk about what iCalendar looks like under the hood.
The “simplest thing that can possibly work” in terms of iCalendar is a text file, with an
.ics extension, that contains the following properties:
<html>…</html>wraps around a web page).
“-//Google Inc//Google Calendar 70.9054//EN”for Google Calendar and
“-//Apple Inc.//Mac OS X 10.14.6//EN”for Apple Calendar.
[buncha-random-chars]@[yourdomain.com]are both common patterns.
Here’s a simple example tying all of that together:
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Example Corp//Example Calendar App 1.0//EN BEGIN:VEVENT UID:[email protected] DTSTAMP:20210310T001345Z DTSTART:19991231T235959 DTEND:20000101T000000 SUMMARY:Party like it’s 1999! END:VEVENT END:VCALENDAR
If you save this as “
y2k.ics” and import it, you should see a new event appear at the very tail end 1999 that lasts from 11:59:59PM on December 31, 1999 until midnight on January 1, 2020!
The RFC gets into this at length, but the basic gist is:
If it’s a date only, it’s specified in the format of
If it’s a date and time, it’s specified in the format of
HH in 24-hour time). If it’s a UTC time (see below) it also has a
Z at the end.
There are three different ways to specify a date and time such as 11:59:59PM on December 31, 1999:
Date with local time: Used when you want an event to be at the same time, regardless of a person’s location.
Date with UTC time: Used when you want an event to be at an absolute time across all geographic locations, and disregarding Daylight Savings Time. (Note: DTSTAMP is always in this format.)
In the above example, we went with the “date with local time” format so that the event would be at the same time regardless of location, since exactly when the “last minute of 1999” is differs across the globe. But for tracking shift schedules, “Date with local time and timezone reference” makes more sense, because if I fly to Europe for work, I don’t want the start times to shift by several hours.
Nope, that semi-colon after
DTSTART in the third example is not a typo. “Property parameters” such as
TZID are passed in with a semicolon rather than a colon. (See List and Field Separators) This will also come into play with...
Ok, so we already have enough information to create each shift schedule the first time, but note that it repeats every X weeks. How do we handle that?
Enter Recurrence Rules (
RRULE)! This property defines a rule or repeating pattern for recurring events. Here are just a few of the options that it supports:
FREQ: How often the event occurs. Some examples are
DAILY, and even
INTERVAL: How many
FREQs should there be in between events?
COUNT: Repeat the event X times. (Useful if you have a class that runs for 4 weeks, for example)
UNTIL: Alternatively, this will repeat the event until a certain date.
BYDAY: Allows you to say something only happens on certain days of the week.
The RFC has all sorts of examples.
For our purposes, we need events that:
INTERVALof 8 since the schedule repeats every 8 weeks.
12/31/2021because the schedule gets reset every calendar year, and next year will be something different! (Hence my very strong desire to write this process down. ;))
Put it all together, and you get:
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Webchick Inc//Webchick’s Crappy Bash Script 1.0//EN BEGIN:VEVENT UID:3231CB09-1E10-4910-BB24-B358629890B7 DTSTAMP:20210314T090733Z SUMMARY:Day Shift DTSTART;TZID=America/Vancouver:20210111T080000 DTEND;TZID=America/Vancouver:20210111T180000 RRULE:FREQ=WEEKLY;INTERVAL=8;UNTIL=20211231 END:VEVENT ... (repeat x many more events) ... BEGIN:VEVENT UID:F20376E5-FA0F-429D-AB1F-3F0155EE10BA DTSTAMP:20210314T090734Z SUMMARY:Evening Shift DTSTART;TZID=America/Vancouver:20210208T173000 DTEND;TZID=America/Vancouver:20210208T233000 RRULE:FREQ=WEEKLY;INTERVAL=8;UNTIL=20211231 END:VEVENT ... (repeat x many more events) ... END:VCALENDAR
And when imported into Apple Calendar:
And there you have it!
So. The next time you get one of those .ics files, try popping it open in a text editor and see how much of it makes sense now!