Back to articles list Articles
6 minutes read

Working With iCalendar in Python

In my previous article on How to Work With the Calendar and Arrow Python Modules, we explored how to use calendars in Python. But what about iCal files? In this article, we will discuss how to work with iCalendar in Python, write and read iCal files, and parse a calendar from a URL like Google Calendar.

But first, what is an iCal file?

The iCalendar (Internet Calendaring and Scheduling Core Object Specification) format allows users to store and exchange calendaring and scheduling information such as events and to-dos. Many products including Google Calendar and Apple Calendar use this format.

Let’s take a look at two popular Python modules that simplify working with .ics files.

How to Read and Write iCalendar Files in Python: The iCalendar Module

icalendar is a popular and convenient library for processing calendars in Python. You need to install it from the pip package:

pip install icalendar

Take a look at its documentation here.

Next, let’s write the code to create a new event and store it on the disk.

We start with the imports. In addition to icalendar, we need datetime, pytz, and pathlib. You can read the details about these packages here and here.

# imports
from icalendar import Calendar, Event, vCalAddress, vText
from datetime import datetime
from pathlib import Path
import os
import pytz

# init the calendar
cal = Calendar()

iCalendar follows the RFC5545 specifications, which means we need to include some properties such as PRODID and Version. PRODID specifies the identifier that created the iCalendar object.

# Some properties are required to be compliant
cal.add('prodid', '-//My calendar product//example.com//')
cal.add('version', '2.0')

Next, we add the event with a name, a description, a start, and an end.

# Add subcomponents
event = Event()
event.add('name', 'Awesome Meeting')
event.add('description', 'Define the roadmap of our awesome project')
event.add('dtstart', datetime(2022, 1, 25, 8, 0, 0, tzinfo=pytz.utc))
event.add('dtend', datetime(2022, 1, 25, 10, 0, 0, tzinfo=pytz.utc))

# Add the organizer
organizer = vCalAddress('MAILTO:jdoe@example.com')

# Add parameters of the event
organizer.params['name'] = vText('John Doe')
organizer.params['role'] = vText('CEO')
event['organizer'] = organizer
event['location'] = vText('New York, USA')

event['uid'] = '2022125T111010/272356262376@example.com'
event.add('priority', 5)
attendee = vCalAddress('MAILTO:rdoe@example.com')
attendee.params['name'] = vText('Richard Roe')
attendee.params['role'] = vText('REQ-PARTICIPANT')
event.add('attendee', attendee, encode=0)

attendee = vCalAddress('MAILTO:jsmith@example.com')
attendee.params['name'] = vText('John Smith')
attendee.params['role'] = vText('REQ-PARTICIPANT')
event.add('attendee', attendee, encode=0)

# Add the event to the calendar
cal.add_component(event)

Finally, we store the event on the disk as example.ics. We create a directory called MyCalendar with pathlib, then we write the event to a file. You can read one of my previous articles here to learn more about writing to a file in Python.

# Write to disk
directory = Path.cwd() / 'MyCalendar'
try:
   directory.mkdir(parents=True, exist_ok=False)
except FileExistsError:
   print("Folder already exists")
else:
   print("Folder was created")

f = open(os.path.join(directory, 'example.ics'), 'wb')
f.write(cal.to_ical())
f.close()

Now that we have created an event, let’s read it.

e = open('MyCalendar/example.ics', 'rb')
ecal = icalendar.Calendar.from_ical(e.read())
for component in ecal.walk():
   print(component.name)
e.close()

The output shows two components:

VCALENDAR
VEVENT

Events are stored in VEVENT. To get the details, we need to access its subcomponents. Note that you need to call the decoded() method instead of get() to output the date and time values.

e = open('MyCalendar/example.ics', 'rb')
ecal = icalendar.Calendar.from_ical(e.read())
for component in ecal.walk():
   if component.name == "VEVENT":
       print(component.get("name"))
       print(component.get("description"))
       print(component.get("organizer"))
       print(component.get("location"))
       print(component.decoded("dtstart"))
       print(component.decoded("dtend"))
e.close()

And here is the output:

Awesome Meeting
Define the roadmap of our awesome project
MAILTO:jdoe@example.com
New York, USA
2022-01-25 08:00:00+00:00
2022-01-25 10:00:00+00:00

There you go! We know how to create an iCal file and read it. Refer to the iCalendar documentation to learn more about the package.

Next, let’s learn about processing a calendar in Python.

Parse a Google Calendar From a URL: The ics Module

We can also parse a Google Calendar URL. For this example, we use the ics.py package, which you can install with the following command:

pip install ics

Let’s use a public Google calendar about the phases of the Moon, parse it as an iCal file, and extract the events.

from ics import Calendar
import requests

# Parse the URL
url = "https://calendar.google.com/calendar/ical/ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com/public/basic.ics"
cal = Calendar(requests.get(url).text)

# Print all the events
print(cal.events)

And here is a part of the output:

{,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,...}

Want to pretty-print it? Take a look at two popular modules for pretty-printing tables here.

Let’s sort the events in descending order using sorted(). We use sorted() instead of fsort() because the events variable is a set, while sort() works with lists.

events = cal.events
sorted_events = sorted(events, reverse = True)
sorted_events

Here is a part of the output:

[,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,
 ,...]

You can learn additional details about sort(), sorted(), and more in my article about working with streams in Python. Feel free to reuse these code snippets and explore the ics.py documentation here.

The ics module can also create iCalendar files. Say you want to add some events to your work calendar to reserve some time each day for your tasks. You want 2 hours each day, and another 1 hour would be nice-to-have. You can do this with the following code:

import arrow
from ics import Calendar, Event

calendar = Calendar()

tz = 'Europe/Paris'
first_day = arrow.get("2022-02-14").replace(tzinfo=tz)
last_day = arrow.get("2022-02-18").replace(tzinfo=tz)

for day in arrow.Arrow.range('day', first_day, last_day):
    event = Event()
    event.name = "Working on the task"
    event.begin = day.replace(hour=8).to('utc').datetime
    event.end = day.replace(hour=10).to('utc').datetime
    event.transparent = False
    calendar.events.add(event)

    event = Event()
    event.name = "Continue on the task?"
    event.begin = day.replace(hour=10).to('utc').datetime
    event.end = day.replace(hour=11).to('utc').datetime
    event.transparent = True
    calendar.events.add(event)

print(calendar) # you can simply save this to a file

Pretty simple, right? You don't have to worry about event IDs or other required iCalendar file attributes. The transparent value defines your availability. True means "transparent" (i.e., "free"), and False means "opaque" (i.e., "busy"). It may not be obvious, but think of it this way: it either needs to show or block the time based on your availability when you search for free/busy times on your calendar.

Also, pay attention to the time zones. The ics module works with UTC values, and you want to set yours before the conversion.

Now, you just have to go to your Google Calendar's settings and import the ics file. You may want to test it on a separate test calendar before adding it to your main calendar as there isn't an easy way to bulk-delete events.

If you want to learn more about data manipulation and programming with Python, I encourage you to join our Python programming track.

Work With iCalendar in Python and More!

We have reviewed how to work with iCalendar files in Python in this article. We have discovered how to create an event, store it as an iCal file, and read it. We have also learned about processing a calendar from a URL and extracting the events from a public Google calendar.

Now, it’s time for you to play with the code to solidify your knowledge. You can also read about good Python practices in my article here to improve your skills.

And learn more Python on LearnPython.com!