Event operations: listing, retrieval, and CRUD against a CalDAV calendar.
Listing uses the REPORT method with a calendar-query filter. Server-side
recurrence expansion via <C:expand> is supported through the
:expand_recurrences option on list/3.
Timed events whose DTSTART/DTEND carry a TZID parameter are normalized
to UTC DateTime values using Tz.TimeZoneDatabase; ambiguous (fall-back)
times resolve to the first occurrence and gap (spring-forward) times to the
time immediately after the gap.
Summary
Functions
Creates a new event resource by PUTing iCalendar data to the calendar.
Deletes an event resource.
Fetches a single event resource by URL.
Lists events from a calendar, optionally filtered by a time range.
Replaces an existing event resource with new iCalendar data.
Types
@type list_opt() :: {:from, DateTime.t() | nil} | {:to, DateTime.t() | nil} | {:expand_recurrences, boolean()}
Options accepted by list/3.
@type list_opts() :: [list_opt()]
Keyword list of list_opt/0 values.
Functions
@spec create(CalDAVEx.Client.t(), String.t(), String.t(), iodata()) :: {:ok, CalDAVEx.Types.Event.t()} | {:error, CalDAVEx.Error.t()}
Creates a new event resource by PUTing iCalendar data to the calendar.
The request includes If-None-Match: * to ensure the operation only
succeeds when no resource exists at the target URL.
Parameters
client- an authenticated%CalDAVEx.Client{}calendar_url- the URL of the parent calendar collectionfilename- the resource filename (e.g."event.ics")ics_data- the iCalendar (VCALENDAR/VEVENT) body as a string
Returns
{:ok, %CalDAVEx.Types.Event{href: url}}on success{:error, %CalDAVEx.Error{}}on failure
@spec delete(CalDAVEx.Client.t(), String.t(), String.t() | nil) :: {:ok, CalDAVEx.HTTP.response()} | {:error, CalDAVEx.Error.t()}
Deletes an event resource.
When etag is provided, the request includes If-Match: <etag> for
optimistic concurrency.
Parameters
client- an authenticated%CalDAVEx.Client{}event_url- the full URL of the event resourceetag- the previously observed ETag, ornilto skip the conditional header
Returns
{:ok, %{status: non_neg_integer, body: term, headers: map}}on success{:error, %CalDAVEx.Error{}}on HTTP, transport, or ETag-mismatch (412) failures
@spec get(CalDAVEx.Client.t(), String.t()) :: {:ok, CalDAVEx.Types.Event.t()} | {:error, CalDAVEx.Error.t()}
Fetches a single event resource by URL.
Returns an event populated with the raw calendar_data body and the
ETag header (when present). Parsed iCalendar fields such as summary or
dtstart are not populated by this function; use list/3 for parsed
results, or parse calendar_data yourself.
Parameters
client- an authenticated%CalDAVEx.Client{}event_url- the full URL of the event resource
Returns
{:ok, %CalDAVEx.Types.Event{}}on success{:error, %CalDAVEx.Error{}}on failure
@spec list(CalDAVEx.Client.t(), String.t(), list_opts()) :: {:ok, [CalDAVEx.Types.Event.t()]} | {:error, CalDAVEx.Error.t()}
Lists events from a calendar, optionally filtered by a time range.
Returned events are not guaranteed to be unique by href or etag: a
single CalDAV resource whose calendar-data contains multiple VEVENT
components (e.g. a recurring master plus RECURRENCE-ID overrides, or
occurrences produced by <C:expand>) yields one %CalDAVEx.Types.Event{}
per VEVENT sharing the same href/etag.
Parameters
client- an authenticated%CalDAVEx.Client{}calendar_url- the full URL of the calendar collectionopts- keyword list::from- start of the time range (DateTime.t/0ornil):to- end of the time range (DateTime.t/0ornil):expand_recurrences- whentrue, asks the server to expand recurring events via<C:expand>. Both:fromand:toMUST be provided when this istrue; otherwise an{:error, %CalDAVEx.Error{type: :invalid_argument}}is returned. Server support varies. Defaults tofalse.
Returns
{:ok, [%CalDAVEx.Types.Event{}]}on success{:error, %CalDAVEx.Error{}}on validation, transport, HTTP, or XML failures
Examples
{:ok, events} = CalDAVEx.Event.list(client, calendar.url,
from: ~U[2025-05-01 00:00:00Z],
to: ~U[2025-05-31 23:59:59Z]
)
@spec update(CalDAVEx.Client.t(), String.t(), iodata(), String.t() | nil) :: {:ok, CalDAVEx.HTTP.response()} | {:error, CalDAVEx.Error.t()}
Replaces an existing event resource with new iCalendar data.
When etag is provided, the request includes If-Match: <etag> to perform
an optimistic-concurrency update; a stale ETag results in a 412 HTTP
error wrapped in CalDAVEx.Error.
Parameters
client- an authenticated%CalDAVEx.Client{}event_url- the full URL of the event resourceics_data- the replacement iCalendar bodyetag- the previously observed ETag, ornilto skip the conditional header
Returns
{:ok, %{status: non_neg_integer, body: term, headers: map}}on success{:error, %CalDAVEx.Error{}}on HTTP, transport, or ETag-mismatch (412) failures