All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.1.4 - 2026-05-21
Fixed
- Fixed iCalendar DTSTART/DTEND parsing to handle TZID parameters (e.g.,
DTSTART;TZID=America/Los_Angeles:20260120T160000) - Events with timezone-aware datetime properties now correctly parse and convert to UTC
- Added proper handling for DST transitions:
- Fall-back (ambiguous times): chooses first occurrence
- Spring-forward (gap times): chooses time after the gap
- Events from Apple Calendar and other iCalendar clients with TZID parameters now parse correctly
- CRITICAL: Fixed timezone database dependency - library now works without consumer config
- All datetime operations use explicit
Tz.TimeZoneDatabaseparameter - Applies to TZID parsing, UTC conversion, and CalDAV time-range formatting
- Previously required consumers to configure
:elixir, :time_zone_databasein their app - Library now works out-of-the-box when added as a dependency
- All datetime operations use explicit
- Fixed RFC5545 compliance: TZID parameter now correctly parsed regardless of position or case
- Handles multiple parameters in any order (e.g.,
DTSTART;VALUE=DATE-TIME;TZID=...) - Case-insensitive property name matching per RFC5545 specification
- Supports quoted TZID parameter values (e.g.,
TZID="America/New_York")
- Handles multiple parameters in any order (e.g.,
Changed
- Improved test coverage with comprehensive test cases for TZID parsing, including:
- Timezone conversion for various timezones
- DST transition handling (fall-back ambiguous and spring-forward gap times)
- Error handling for invalid timezones and malformed datetimes
- Backward compatibility with UTC and DATE formats
- RFC5545 compliance (multiple parameters, quoted values, case-insensitivity)
- Performance optimization: precompiled TZID extraction regexes at module compile-time
- Eliminates repeated regex compilation overhead when processing multiple events
- Zero runtime cost for regex compilation
- Stricter datetime validation: regex now enforces exact iCalendar DATE-TIME format (YYYYMMDDTHHmmss)
- Rejects malformed datetime values early (e.g., extra digits, missing separators)
- Prevents partial matches on invalid input
- RFC5545 line unfolding: properly handles continuation lines in iCalendar data
- Unfolds lines that begin with space or tab per RFC5545 section 3.1
- Ensures TZID extraction works with folded properties and XML-indented content
- Improved error handling: replaced bang functions with explicit error handling
- Uses
DateTime.shift_zone/3instead ofshift_zone!/2with blanket rescue - Explicit handling of
{:ok, dt}and{:error, reason}for better debugging - Separated timezone resolution logic for clarity
- Uses
0.1.0 - 2026-05-19
Added
- Initial release
- CalDAV discovery (current-user-principal and calendar-home-set)
- Calendar listing with display name, description, and ctag
- Event listing with time-range filtering
- Single event retrieval by URL
- Robust XML parsing using Saxy
- iCalendar parsing via ical library
- Support for both timed and all-day events
- Basic and no-auth authentication methods
- Comprehensive test suite with Bypass HTTP mocking
Features
CalDAVEx.discover/1- Discover principal and calendar home setCalDAVEx.list_calendars/2- List all calendarsCalDAVEx.list_events/3- List events with optional time filteringCalDAVEx.get_event/2- Retrieve a single event by URLCalDAVEx.new_config/2- Create client configurationCalDAVEx.new_client/1- Create CalDAV clientCalDAVEx.basic_auth/2- Basic authenticationCalDAVEx.no_auth/0- No authentication