# `Tempo.RRule`
[🔗](https://github.com/kipcole9/tempo/blob/v0.5.0/lib/tempo/rrule.ex#L1)

Parses [iCalendar RFC 5545](https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.10)
`RRULE` strings into Tempo AST (`%Tempo.Interval{}` with a
`%Tempo.Duration{}` cadence and, where needed, a `repeat_rule`
built from selection tokens).

This module is intentionally small — it exists to validate that
Tempo's AST is a sufficient target for recurrence rules expressed
in formats other than ISO 8601-2. See
`docs/rrule-ast-validation.md` for findings.

## Supported rule parts

* `FREQ` — `SECONDLY` | `MINUTELY` | `HOURLY` | `DAILY` | `WEEKLY`
  | `MONTHLY` | `YEARLY`

* `INTERVAL` — positive integer, default `1`

* `COUNT` — positive integer (mutually exclusive with `UNTIL`)

* `UNTIL` — basic-format ISO 8601 date or date-time

* `BYMONTH`, `BYMONTHDAY`, `BYYEARDAY`, `BYWEEKNO`, `BYHOUR`,
  `BYMINUTE`, `BYSECOND` — comma-separated (optionally negative)
  integer list

* `BYDAY` — comma-separated list where each entry is
  `[<sign><ordinal>]<weekday>` (e.g. `MO`, `-1FR`, `4TH`)

* `BYSETPOS` — comma-separated integer list

* `WKST` — weekday code

## Returns

`{:ok, %Tempo.Interval{}}` on success.

## Examples

    iex> {:ok, %Tempo.Interval{} = i} = Tempo.RRule.parse("FREQ=DAILY;COUNT=10")
    iex> {i.recurrence, i.duration.time}
    {10, [day: 1]}

    iex> {:ok, i} = Tempo.RRule.parse("FREQ=WEEKLY;INTERVAL=2;UNTIL=20221231")
    iex> i.duration.time
    [week: 2]

# `parse`

```elixir
@spec parse(
  binary(),
  keyword()
) :: {:ok, Tempo.Interval.t()} | {:error, term()}
```

Parse an RRULE string into a `%Tempo.Interval{}` AST node.

### Arguments

* `rrule` is a string in RRULE form (with or without the
  leading `RRULE:` prefix).

### Options

* `:from` — a `%Tempo{}` anchor (DTSTART). Sets `Interval.from`
  so occurrence enumeration has a starting point. Optional;
  callers that intend to enumerate must supply this.

### Returns

* `{:ok, %Tempo.Interval{}}` on success.

* `{:error, reason}` on a malformed rule or unknown keyword.

### Examples

    iex> {:ok, i} = Tempo.RRule.parse("FREQ=DAILY;COUNT=10")
    iex> i.recurrence
    10

    iex> {:error, _} = Tempo.RRule.parse("FREQ=NOPE")

# `parse!`

```elixir
@spec parse!(
  binary(),
  keyword()
) :: Tempo.Interval.t()
```

Bang variant of `parse/2`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
