JSCalendar.Event (JSCalendar v0.1.0)

Copy Markdown View Source

Something that happens at a particular time (RFC 8984 ยง5.1).

An event has a start and a duration rather than a start and an end. That is not a stylistic choice: the end of an event is start + duration in the event's own time zone, so an hour-long meeting stays an hour long across a daylight-saving boundary, where a stored end time would silently become two hours or none.

start is a LocalDateTime โ€” wall-clock, with no offset โ€” and time_zone names the zone it is read in. A nil time zone means a floating event: the same wall-clock time wherever the reader is, which is what "New Year's Eve, midnight" actually means.

Example

iex> {:ok, event} = JSCalendar.Event.from_map(%{
...>   "@type" => "Event",
...>   "uid" => "review-2026-06",
...>   "updated" => "2026-06-01T09:00:00Z",
...>   "title" => "Quarterly review",
...>   "start" => "2026-06-02T09:00:00",
...>   "timeZone" => "Australia/Sydney",
...>   "duration" => "PT1H"
...> })
iex> {event.title, event.start, event.duration}
{"Quarterly review", ~N[2026-06-02 09:00:00], %Duration{hour: 1}}

Summary

Types

t()

A calendar event.

Functions

The event's duration, defaulting as RFC 8984 requires.

When the event ends, in its own time zone.

Read this object from a decoded JSON map.

The @type value RFC 8984 gives this object.

Write this object back to a JSON-ready map.

Types

t()

@type t() :: %JSCalendar.Event{
  alerts: term(),
  categories: term(),
  color: term(),
  created: term(),
  description: String.t(),
  description_content_type: term(),
  duration: Duration.t() | nil,
  excluded: term(),
  excluded_recurrence_rules: term(),
  extra: map(),
  free_busy_status: term(),
  keywords: term(),
  links: term(),
  locale: term(),
  localizations: %{optional(String.t()) => JSCalendar.Patch.t()} | nil,
  locations: %{optional(String.t()) => JSCalendar.Location.t()} | nil,
  method: term(),
  participants: %{optional(String.t()) => JSCalendar.Participant.t()} | nil,
  priority: term(),
  privacy: term(),
  prod_id: term(),
  recurrence_id: term(),
  recurrence_id_time_zone: term(),
  recurrence_overrides:
    %{optional(NaiveDateTime.t()) => JSCalendar.Patch.t()} | nil,
  recurrence_rules: [JSCalendar.RecurrenceRule.t()] | nil,
  related_to: term(),
  reply_to: term(),
  request_status: term(),
  sent_by: term(),
  sequence: term(),
  show_without_time: term(),
  start: NaiveDateTime.t() | nil,
  status: String.t() | nil,
  time_zone: String.t() | nil,
  time_zones: %{optional(String.t()) => JSCalendar.TimeZone.t()} | nil,
  title: String.t(),
  uid: String.t() | nil,
  updated: term(),
  use_default_alerts: term(),
  virtual_locations: term()
}

A calendar event.

Functions

duration(event)

@spec duration(t()) :: Duration.t()

The event's duration, defaulting as RFC 8984 requires.

duration is optional and defaults to PT0S when absent, so an event with no duration is an instant rather than one of unknown length. Reading the field directly gives nil; this gives the meaning.

Arguments

  • event is a t/0.

Returns

Examples

iex> JSCalendar.Event.duration(%JSCalendar.Event{duration: %Duration{hour: 1}})
%Duration{hour: 1}

iex> JSCalendar.Event.duration(%JSCalendar.Event{})
%Duration{}

ends_at(event)

@spec ends_at(t()) :: NaiveDateTime.t() | nil

When the event ends, in its own time zone.

Arguments

  • event is a t/0.

Returns

Examples

iex> event = %JSCalendar.Event{start: ~N[2026-06-02 09:00:00], duration: %Duration{hour: 1}}
iex> JSCalendar.Event.ends_at(event)
~N[2026-06-02 10:00:00]

from_map(map)

@spec from_map(map()) :: {:ok, struct()} | {:error, term()}

Read this object from a decoded JSON map.

Arguments

Returns

  • {:ok, object}; or

  • {:error, reason} when a property does not match its declared type.

jscalendar_type()

@spec jscalendar_type() :: String.t()

The @type value RFC 8984 gives this object.

Returns

  • the type name as a string.

to_map(object)

@spec to_map(struct()) :: map()

Write this object back to a JSON-ready map.

Arguments

  • object is a t/0.

Returns