README.md

# ICal

A library for reading and writing iCalendar data.

## Features

* Parsing iCalendar data from strings or files
* Serializing iCalendar data to iolists suitable for writing out to files, send over the network, etc.
* Integration with Plug / Phoenix via `ICal.encode_to_iodata`
* Components supported
  * Events (with alarms)
  * Todos (with alarms)
  * Journals
  * Timezones
  * Alarms
* Recurrence calculations
* Alarm calculations
* Compatibility
  * RFC 5545 compliant
  * Support for common non-standard properties, including:
      * `X-WR-TIMEZONE`
      * `X-WR-CALNAME`/`NAME`
  * Timezones are resolved using the system timezone library, supporting variants seen in the wild
  * All`X-*` fields and valid-by-not-yet-supported fields are retained

### Future work

Components that will eventually be supported (in rough order):

* Free/busy (VFREEBUSY)

## Usage

Full documentation can be found on [Hexdocs](https://hexdocs.pm/ical).

The primary entry points are `ICal.from_ics/1` and `ICal.from_file/1` for parsing iCalendar data,
and `ICal.to_ics/1` for serializing an `%ICal{}` to an `iodata` ready for writing to a file, sending
over the network, etc.

```elixir
calendar = ICal.from_file(ical_path)
%ICal{events: events} = calendar
ics_iodata = ICal.to_ics(calendar)
```

To accommodate applications which use `rrule` strings on their own, `ICal.Recurrence` structs can
be created these strings using `ICal.Recurrence.from_ics/1`:

```elixir
ICal.Recurrence.from_ics("RRULE:RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7")
```

Recurrence dates may be calculated from either a calendar component or a `%ICal.Recurrence{}` using
the `ICal.Recurrence.stream/2` function, while alarms may be resolved using `ICal.Alarm.next_alarms/1`.

Inline attachments can be decoded via `ICal.Attachment.decoded_data/1`.

## Installation

- Add `:ical` to your list of dependencies in `mix.exs`, along with a timezone database:

  ```elixir
  def deps do
    [{:ical, "~> 1.0"}]
      {:ical, "~> 1.0"},
      {:tz, "~> 1.1"}
    ]
  end
  ```

  Then configure the timezone database in e.g. `config/config.exs`:

  ```elixir
  config :elixir, :time_zone_database, Tz.TimeZoneDatabase
  ```
  For auto-updating the timezone database at runtime, check the documentation for the timezone
  library you are using.

  The following timezone database packages are known to work well with ICal:

  | Package | Module |
  |---|---|
  | [`tz`](https://hex.pm/packages/tz) | `Tz.TimeZoneDatabase` |
  | [`time_zone_info`](https://hex.pm/packages/time_zone_info) | `TimeZoneInfo.TimeZoneDatabase` |

  See [tzdb_test](https://github.com/mathieuprog/tzdb_test) for more
  information on the available timezone database libraries.

## Goals

* corrrect: support the iCalendar (and its related) RFCs for standards-compliance
* useful: handle real-world data (such as produced by other clients) gracefully, do
  not lose data while parsing (including fields not supported by / used in this library)
* good developer experience
  * parsed results should be easy to use, even if iCalednar is a complex format
  * typed structs and clear APIs
  * good doucmentation
* resource friendly: be performant in parsing and serializing
* reliable: be well-tested, beyond just code coverage

## Participating in development

Visit the [issue tracker](https://github.com/expothecary/icalendar/issues) to see what
tasks are outstanding. You are welcome to file new issues, as well!

PRs are welcome and responded to in a timely fashion.

Benchee is used for benchmarking, credo for linting, and the test suite must pass before
PRs are merged. New functionality and bug fixes must have accompanying unit tests.