README.md

# ExCycle

`ExCycle` is a powerful library to generate datetimes following RRules from iCalendar.

```elixir
iex> ExCycle.new()
...> |> ExCycle.add_rule(:daily, interval: 2, hours: [20, 10]
...> |> ExCycle.add_rule(:daily, interval: 1, hours: [15]
...> |> ExCycle.occurrences(~D[2024-02-29]
...> |> Enum.take(5)
[~N[2024-02-29 10:00:00], ~N[2024-02-29 15:00:00], ~N[2024-02-29 20:00:00], ~N[2024-03-01 15:00:00], ~N[2024-03-02 10:00:00]]
```

## Installation

`ExCycle` is available on [Hex](https://hex.pm/packages/ex_cycle) and can be installed
by adding `ex_cycle` to your list of dependencies in `mix.exs`.

```elixir
def deps do
  [
    {:ex_cycle, "~> 0.1.0"}
  ]
end
```

## Time zone database

ExCycle support timezones and require a time zone database.
By default, it uses the default time zone database returned by
`Calendar.get_time_zone_database/0`, which defaults to
`Calendar.UTCOnlyTimeZoneDatabase` which only handles "Etc/UTC"
datetimes and returns `{:error, :utc_only_time_zone_database}`
for any other time zone.

Other time zone databases can also be configured. For example,
two of the available options are:

* [`tz`](https://hexdocs.pm/tz/)
* [`tzdata`](https://hexdocs.pm/tzdata/)

To use them, first make sure it is added as a dependency in `mix.exs`.
It can then be configured either via configuration:

```elixir
config :elixir, :time_zone_database, Tzdata.TimeZoneDatabase
```

or by calling `Calendar.put_time_zone_database/1`:

```elixir
Calendar.put_time_zone_database(Tzdata.TimeZoneDatabase)
```

See the proper names in the library installation instructions.

> We apply the same logic as [DateTime from elixir](https://hexdocs.pm/elixir/DateTime.html).

## Documentation

Full documentation could be found at <https://hexdocs.pm/ex_cycle>.

## Quick-start Guide

Create a *cycle* and add rules

```elixir
ExCycle.new()
|> ExCycle.add_rule(:daily, hours: [20, 10])
|> ExCycle.add_rule(:daily, interval: 2, hours: [15])

# Generates every day at 10:00 and 20:00 and every 2 days at 15:00
```

The first element is the frequency that could be one of `secondly`, `minutely`, `hourly`,
`daily`, `monthly` or `yearly`. Then the 2nd parameter is a list of validations options
(like every hours at X).

You can specified a duration using the option `:duration`. The value uses the `Duration` structured, introduced
in elixir `1.17`.

> For every Elixir's versions before `1.17`, we have been cloned this structure to obtain the same behaviour.


### Options

Here the list of option that you can use to generate the rule (using `ExCycle.add_rule/3`).

- `:interval`
- `:hours`
- `:minutes`

### Timezones

As we mention earlier, we support timezone and you can easily generate datetime using the option `timezone: "America/Montreal"` as the code bellow.

```elixir
ExCycle.new()
|> ExCycle.add_rule(:daily, hours: [20, 10], timezone: "America/Montreal")

# Generates every day at 10:00 and 20:00 with timezone America/Montreal
```

### Span

ExCycle support `duration` (using the structs from elixir 1.17), to generates span

```elixir
ExCycle.new()
|> ExCycle.add_rule(:daily, hours: [10], duration: %Duration{hour: 2})
```

This could be combined with `timezone` option to generate span using timezone (**with** DST support).

```elixir
ExCycle.new()
|> ExCycle.add_rule(:daily, hours: [10], duration: %Duration{hour: 2}, timezone: "America/Montreal")

# Generates every day from 10:00 to 12:00 with timezone America/Montreal
```

## Credits

`ExCycle` is inspired by [Cocktail](https://github.com/peek-travel/cocktail). ExCycle's goal is to improve the handling of Timezones and DST.