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+.

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)

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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ical-14.0.1.tar.gz (152.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ical-14.0.1-py3-none-any.whl (141.2 kB view details)

Uploaded Python 3

File details

Details for the file ical-14.0.1.tar.gz.

File metadata

  • Download URL: ical-14.0.1.tar.gz
  • Upload date:
  • Size: 152.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for ical-14.0.1.tar.gz
Algorithm Hash digest
SHA256 444df95a8eb710d87a196fd995b26f0ff7fcf8f779e9eeae898b4393a492be6d
MD5 4e16e079ce6d7f362c39fa0bdcd00965
BLAKE2b-256 050e8cdeb5e10f5ab7290d8affe256d1373635d33856b98a27688795d3b0f314

See more details on using hashes here.

Provenance

The following attestation bundles were made for ical-14.0.1.tar.gz:

Publisher: publish.yaml on allenporter/ical

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ical-14.0.1-py3-none-any.whl.

File metadata

  • Download URL: ical-14.0.1-py3-none-any.whl
  • Upload date:
  • Size: 141.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for ical-14.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 02ca21f76a7899dbc093b301d2fd2ce2a36c06a9a53e2cec442d80210724737f
MD5 2261f2257005d174a19b295189d26bb9
BLAKE2b-256 7fc63cc02d2bebf838126b4d3bed4800b108079a3e82cd39f2374bc6256733c6

See more details on using hashes here.

Provenance

The following attestation bundles were made for ical-14.0.1-py3-none-any.whl:

Publisher: publish.yaml on allenporter/ical

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page