Skip to main content

ical

PyPI version CI Documentation

A modern Python RFC 5545 iCalendar library with built-in recurring event support — no companion libraries needed.

from ical.calendar_stream import IcsCalendarStream

cal = IcsCalendarStream.calendar_from_ics(ics_content)

# Recurring events are automatically expanded — just iterate
for event in cal.timeline:
    print(event.start, event.summary)

Why ical?

Most Python iCalendar libraries require two separate packages to handle recurring events:

# The typical ecosystem approach — two libraries, two APIs
import icalendar
import recurring_ical_events

cal = icalendar.Calendar.from_ical(ics_content)
events = recurring_ical_events.of(cal).between(start, end)

ical handles this natively with a single, unified Timeline interface, with a Pythonic API and validated inputs.

Feature ical icalendar ics.py
Built-in recurrence expansion ❌ needs recurring-ical-events
Pythonic attribute access (event.start, event.summary) ❌ (event.get('DTSTART').dt)
Input validation with clear error messages
Full type annotations (py.typed) ✅ strict ty ✅ v7+
Application-level store API
RFC 7986 / RFC 6868 / RFC 8536 partial
Active maintenance ⚠️ stalled

Used By

Installation

uv add ical

Or with pip:

pip install ical

Requires Python 3.11+.

Fetching calendars from a url asynchronously (see below) requires the optional async extra, which pulls in aiohttp:

pip install ical[async]

Quickstart

Reading an .ics file

Parse a calendar file and iterate over events in chronological order, with recurring events automatically expanded:

from pathlib import Path
from ical.calendar_stream import IcsCalendarStream
from ical.exceptions import CalendarParseError

filename = Path("calendar.ics")
with filename.open() as ics_file:
    try:
        cal = IcsCalendarStream.calendar_from_ics(ics_file.read())
    except CalendarParseError as err:
        print(f"Failed to parse '{filename}': {err}")
    else:
        for event in cal.timeline:
            print(event.start, event.summary)

Fetching a remote .ics url

Fetching a remote calendar over HTTP without blocking the event loop requires the optional ical[async] extra:

from ical.calendar_stream import IcsCalendarStream

cal = await IcsCalendarStream.calendar_from_url("https://example.com/calendar.ics")
for event in cal.timeline:
    print(event.start, event.summary)

An existing aiohttp.ClientSession can be passed in via the session argument to reuse connection pooling; otherwise a session is created and closed automatically for the request.

Creating a calendar

from datetime import date
from ical.calendar import Calendar
from ical.event import Event

cal = Calendar()
cal.events.append(
    Event(summary="Team standup", start=date(2024, 1, 15), end=date(2024, 1, 16)),
)
for event in cal.timeline:
    print(event.summary)

Writing an .ics file

from pathlib import Path
from ical.calendar_stream import IcsCalendarStream

with Path("output.ics").open("w") as f:
    f.write(IcsCalendarStream.calendar_to_ics(cal))

Recurring events

Recurring events are stored once in the calendar but automatically expanded by the Timeline:

from datetime import date
from ical.calendar import Calendar
from ical.event import Event
from ical.types.recur import Recur

cal = Calendar()
cal.events.append(
    Event(
        summary="Weekly standup",
        start=date(2024, 1, 15),
        end=date(2024, 1, 16),
        rrule=Recur.from_rrule("FREQ=WEEKLY;COUNT=10"),
    )
)

# All 10 occurrences are expanded automatically
for event in cal.timeline:
    print(event.start, event.summary)

Application-level API

For managing calendar state in an application (ensuring timezones are set correctly, editing individual instances of recurring events, etc.), use ical.store:

from ical.store import EventStore
from ical.event import Event
from datetime import datetime, timezone

store = EventStore()
store.add(Event(summary="Meeting", start=datetime(2024, 1, 15, 9, tzinfo=timezone.utc)))

See the full documentation for the complete API reference.

Technical Guides

We publish detailed technical guides exploring the library's design:

Supported RFCs

  • RFC 5545 — Internet Calendaring and Scheduling Core Object Specification (iCalendar)
  • RFC 6868 — Parameter Value Encoding in iCalendar and vCard
  • RFC 7986 — New Properties for iCalendar
  • RFC 8536 — The Time Zone Information Format (TZif)

Comparison with other libraries

ical is designed for applications that need a complete, modern solution. You may prefer an alternative if:

  • icalendar — You need low-level control over raw iCalendar components, jCal (JSON) support, or maximum ecosystem compatibility. You prefer to expand recurring events manually and don't mind a second library (recurring-ical-events). You need to support legacy Python versions (3.8+) that ical does not target.
  • ics.py — You need a simple read-only script and do not require recurrence support. Note: no stable release since 0.7.2 (August 2021).

Contributing

See CONTRIBUTING.md for setup and development instructions.

Release files for ical 14.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ical 14.2.0
File Size Uploaded
ical-14.2.0.tar.gz 158.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ical 14.2.0
File Interpreter ABI Platform
ical-14.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 304.0 kB

Release files / ical-14.2.0.tar.gz

Download URL ical-14.2.0.tar.gz
Size 158.4 kB
Tags Source
SHA-256 checksum
How to use checksums
9b14d5a410eee8c5798df000ebc5e3f678067fb83ca4b34abdfa61fa47ddb3ef
BLAKE2b-256 checksum
How to use checksums
b31e575e61ed543111c69aec31e2acbe920f4d06a5a30e739706be3f597754dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / ical-14.2.0-py3-none-any.whl

Download URL ical-14.2.0-py3-none-any.whl
Size 145.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
77c4ddbdea48fd3a5b21fa7a92daaa0be6904dc01b08f2cc6114f59bd9346229
BLAKE2b-256 checksum
How to use checksums
523aaf15ead88ff40eb9cf5e8232b5237d561178b7f7660c105ae9f50d8a259e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

14.2.0 This release

2 release files

14.1.1

2 release files

14.0.1

2 release files

13.3.0

2 release files

13.2.5

2 release files

13.2.4

2 release files

13.2.3

2 release files

13.2.2

2 release files

13.2.1

2 release files

13.2.0

2 release files

13.1.0

2 release files

13.0.1

2 release files

12.1.3

2 release files

12.1.2

2 release files

12.1.1

2 release files

12.1.0

2 release files

12.0.0

2 release files

11.1.0

2 release files

11.0.0

2 release files

10.0.4

2 release files

10.0.3

2 release files

10.0.2

2 release files

10.0.0

2 release files

9.2.5

2 release files

9.2.4

2 release files

9.2.3

2 release files

9.2.2

2 release files

9.2.1

2 release files

9.2.0

2 release files

9.1.0

2 release files

9.0.3

2 release files

9.0.2

2 release files

9.0.1

2 release files

8.3.1

2 release files

8.3.0

2 release files

8.2.0

2 release files

8.1.1

2 release files

8.1.0

2 release files

8.0.2

2 release files

8.0.1

2 release files

8.0.0

2 release files

7.0.3

2 release files

7.0.2

2 release files

7.0.1

2 release files

7.0.0

2 release files

6.1.1

2 release files

6.1.0

2 release files

6.0.0

2 release files

5.1.1

2 release files

5.1.0

2 release files

5.0.1

2 release files

5.0.0

2 release files

4.5.4

2 release files

4.5.2

2 release files

4.5.1

2 release files

4.5.0

2 release files

4.4.0

2 release files

4.3.0

2 release files

4.2.9

2 release files

4.2.8

2 release files

4.2.7

2 release files

4.2.6

2 release files

4.2.5

2 release files

4.2.4

2 release files

4.2.3

2 release files

4.2.2

2 release files

4.2.1

2 release files

4.2.0

2 release files

4.1.2

2 release files

4.1.1

2 release files

4.1.0

2 release files

4.0.1

2 release files

4.0.0

2 release files

3.0.1

2 release files

3.0.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page