ezcal 0.3.4

Ergonomic iCalendar + vCard library for Rust
Documentation
use ezcal::ical::Calendar;

fn main() {
    // Example .ics content (normally you'd read from a file)
    let ics_content = "\
BEGIN:VCALENDAR\r\n\
VERSION:2.0\r\n\
PRODID:-//Google Inc//Google Calendar 70.9054//EN\r\n\
CALSCALE:GREGORIAN\r\n\
X-WR-CALNAME:Work Calendar\r\n\
BEGIN:VEVENT\r\n\
UID:abc123@google.com\r\n\
DTSTAMP:20260315T120000Z\r\n\
DTSTART;TZID=America/New_York:20260315T090000\r\n\
DTEND;TZID=America/New_York:20260315T100000\r\n\
SUMMARY:Sprint Planning\r\n\
DESCRIPTION:Plan the next sprint\\nDiscuss priorities\r\n\
LOCATION:Conference Room A\r\n\
STATUS:CONFIRMED\r\n\
CATEGORIES:MEETING,WORK\r\n\
RRULE:FREQ=WEEKLY;BYDAY=MO;COUNT=12\r\n\
BEGIN:VALARM\r\n\
ACTION:DISPLAY\r\n\
DESCRIPTION:Meeting starts soon\r\n\
TRIGGER:-PT10M\r\n\
END:VALARM\r\n\
END:VEVENT\r\n\
BEGIN:VEVENT\r\n\
UID:def456@google.com\r\n\
DTSTAMP:20260315T120000Z\r\n\
DTSTART;VALUE=DATE:20260320\r\n\
SUMMARY:Company Holiday\r\n\
STATUS:CONFIRMED\r\n\
END:VEVENT\r\n\
BEGIN:VTODO\r\n\
UID:todo789@google.com\r\n\
DTSTAMP:20260315T120000Z\r\n\
SUMMARY:Review PRs\r\n\
DUE:20260316T170000\r\n\
STATUS:NEEDS-ACTION\r\n\
PRIORITY:3\r\n\
END:VTODO\r\n\
END:VCALENDAR\r\n";

    // Parse the calendar
    let calendar = Calendar::parse(ics_content).unwrap();

    println!("Calendar: {}", calendar.get_name().unwrap_or("(unnamed)"));
    println!("Producer: {}", calendar.get_prodid());
    println!();

    // List all events
    println!("Events ({}):", calendar.events().len());
    for event in calendar.events() {
        let summary = event.get_summary().unwrap_or("(untitled)");
        let location = event.get_location().unwrap_or("(no location)");

        if let Some(start) = event.get_starts() {
            if start.is_date() {
                println!("  [All-day] {} - {}", start, summary);
            } else {
                println!("  {} - {} @ {}", start, summary, location);
            }
        }

        if let Some(rrule) = event.get_rrule() {
            println!("    Recurs: {}", rrule);
        }

        if !event.get_alarms().is_empty() {
            println!("    Alarms: {}", event.get_alarms().len());
        }

        if !event.get_categories().is_empty() {
            println!("    Categories: {}", event.get_categories().join(", "));
        }
    }

    println!();

    // List all todos
    println!("Todos ({}):", calendar.todos().len());
    for todo in calendar.todos() {
        let summary = todo.get_summary().unwrap_or("(untitled)");
        let status = todo.get_status().unwrap_or("(no status)");
        println!("  {} [{}]", summary, status);
        if let Some(due) = todo.get_due() {
            println!("    Due: {}", due);
        }
    }
}