Text::JSCalendar - Convert between iCalendar and JSCalendar DESCRIPTION Text::JSCalendar provides bidirectional conversion between iCalendar (RFC 5545) and JSCalendar, following the latest drafts: - draft-ietf-calext-jscalendar-icalendar (mapping specification) - draft-ietf-calext-jscalendarbis (JSCalendar data model) - draft-ietf-calext-icalendar-jscalendar-extensions (new iCal properties) METHODS $jscal = Text::JSCalendar->new() Create a converter instance. Caches timezone objects for performance. @events = $jscal->vcalendarToEvents($ical_string) Parse an iCalendar string (VCALENDAR with VEVENT or VTODO components) and return a list of JSCalendar Event or Task hashrefs. $ical_string = $jscal->eventsToVCalendar(@events) Convert one or more JSCalendar Event/Task hashrefs to an iCalendar string with VTIMEZONE components automatically included. $normalized = Text::JSCalendar->NormaliseEvent($event) Return a copy of the event with default-valued properties removed. Useful for comparison and storage. $bool = Text::JSCalendar->CompareEvents($event1, $event2) Compare two events after normalization. Returns true if identical. CONVERSION DESIGN The module converts between two representations of the same data: iCalendar (RFC 5545) JSCalendar (draft-jscalendarbis) ======================== ============================== VEVENT <=> Event (@type: "Event") VTODO <=> Task (@type: "Task") DTSTART + DTEND/DURATION <=> start + duration + timeZone RRULE <=> recurrenceRule EXDATE / RDATE <=> recurrenceOverrides RECURRENCE-ID <=> recurrenceOverrides (patches) ATTENDEE / ORGANIZER <=> participants + replyTo VALARM <=> alerts ATTACH / URL / IMAGE <=> links CONFERENCE <=> virtualLocations CATEGORIES <=> keywords RELATED-TO <=> relatedTo Property Mapping iCalendar Property JSCalendar Property ------------------------- ---------------------------- UID uid SUMMARY title DESCRIPTION description STYLED-DESCRIPTION description + descriptionContentType DTSTART start + timeZone DTEND (computed as duration) DURATION duration DTSTART TZID (end differs) endTimeZone STATUS status TRANSP freeBusyStatus ("free"/"busy") CLASS privacy ("private"/"confidential"/"public") PRIORITY priority (0-9) COLOR color LOCATION locations[].name GEO locations[].coordinates CONFERENCE virtualLocations[].uri + features SHOW-WITHOUT-TIME showWithoutTime CREATED created DTSTAMP / LAST-MODIFIED updated / lastModified SEQUENCE sequence PRODID prodId ORGANIZER organizerCalendarAddress + participant ATTENDEE participants[] VALARM alerts[] ATTACH links[] (rel: "enclosure") URL links[] IMAGE links[] (rel: "icon") CATEGORIES keywords RELATED-TO relatedTo RRULE recurrenceRule EXDATE recurrenceOverrides (excluded: true) RDATE recurrenceOverrides (empty patch) RECURRENCE-ID recurrenceOverrides (computed patch) Task-specific (VTODO): DUE due PERCENT-COMPLETE percentComplete ESTIMATED-DURATION estimatedDuration COMPLETED / STATUS progress Participant Mapping ATTENDEE Parameter JSCalendar Property ------------------------- ---------------------------- CN name EMAIL email CUTYPE kind PARTSTAT participationStatus ROLE=CHAIR roles: [chair] ROLE=OWNER roles: [owner] ROLE=OPT-PARTICIPANT attendance: optional ROLE=NON-PARTICIPANT attendance: none RSVP expectReply SCHEDULE-AGENT scheduleAgent DELEGATED-FROM delegatedFrom DELEGATED-TO delegatedTo X-SEQUENCE scheduleSequence X-DTSTAMP scheduleUpdated APPLE ICALENDAR EXTENSIONS Apple's Calendar app (macOS/iOS) uses several proprietary iCalendar extensions. There is no formal Apple specification for these; our implementation is based on reverse-engineering and community sources: - X-APPLE-STRUCTURED-LOCATION format examples https://github.com/collective/icalendar/issues/116 https://github.com/icalendar/icalendar/issues/108 - Apple iCalendar property analysis https://spaceraccoon.dev/exploiting-icalendar-properties-enterprise-applications/ - iCalendar non-standard properties overview https://en.wikipedia.org/wiki/ICalendar - RFC 9073 (standardized alternative to Apple structured data) https://www.rfc-editor.org/rfc/rfc9073.html Reading Apple Extensions X-APPLE-STRUCTURED-LOCATION Parsed into locations[] with: - geo: URI value -> coordinates - X-TITLE parameter -> name - X-ADDRESS parameter -> description When both X-APPLE-STRUCTURED-LOCATION and GEO are present on the same event, the Apple property takes precedence (it is a superset of GEO with additional metadata). X-APPLE-DEFAULT-ALARM When a VALARM has X-APPLE-DEFAULT-ALARM:TRUE, the event's useDefaultAlerts is set to true. X-WR-ALARMUID Used as a fallback alarm identifier when the standard UID property is missing from a VALARM. Writing Apple Extensions When generating iCalendar output: - Locations with coordinates AND a name or description are written as X-APPLE-STRUCTURED-LOCATION (with X-TITLE and X-ADDRESS parameters) instead of plain GEO. This ensures Apple Calendar displays the location on a map with the correct title. - Locations with coordinates but no additional metadata are written as standard GEO properties. - This approach ensures that: 1. Apple Calendar gets rich location data it can display 2. Other clients get standard GEO they can parse 3. Round-trips through our converter are stable Properties we do NOT generate (low interop value): - X-APPLE-TRAVEL-DURATION (no JSCalendar equivalent) - X-APPLE-TRAVEL-ADVISORY-BEHAVIOR (no JSCalendar equivalent) - X-APPLE-MAPKIT-HANDLE (binary plist, opaque) TIMEZONE HANDLING The module includes Text::JSCalendar::TimeZones which contains auto-generated VTIMEZONE data for all IANA timezone identifiers. Timezone lookup uses fuzzy matching (Text::LevenshteinXS) to handle non-standard TZID values from various calendar implementations. When generating iCalendar output, VTIMEZONE components are automatically included for all timezones referenced by events. TESTING t/api.t - Gold-file comparison tests (parse + roundtrip) t/icalfiles.t - Roundtrip normalization tests t/cyrus-caldav.t - Live Cyrus CalDAV/JMAP integration tests (set CYRUS_URL, CYRUS_USER, CYRUS_PASS to enable) The Cyrus integration tests verify: - CalDAV PUT/GET roundtrip for events with various properties - End timezone handling - GEO coordinate preservation - CONFERENCE/virtualLocations - VTODO/Task support - JMAP CalendarEvent creation and comparison with our conversion SPECIFICATIONS RFC 5545 - Internet Calendaring (iCalendar) RFC 7986 - New Properties for iCalendar RFC 9073 - Event Publishing Extensions to iCalendar draft-ietf-calext-jscalendarbis JSCalendar: A JSON Representation of Calendar Data draft-ietf-calext-jscalendar-icalendar JSCalendar: Converting from and to iCalendar draft-ietf-calext-icalendar-jscalendar-extensions iCalendar Format Extensions for JSCalendar AUTHOR Bron Gondwana LICENSE Copyright 2019-2026 FastMail Pty Ltd. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself (Artistic License 2.0).