# `Tempo.Event`
[🔗](https://github.com/elixir-tempo/tempo/blob/v2.1.0/lib/tempo/event.ex#L1)

The date of a named computed event in a year: an event fixed by an
algorithm rather than by the calendar.

Four families are built in: Easter, Western and Orthodox, from
`Calendrical.Ecclesiastical`; the equinoxes and solstices and the first
new moon of the year, from `Astro`; and the twenty-four solar terms
(jié-qì) of the East Asian calendars, from `Calendrical`, reckoned at the
meridian of the calendar asked. A consumer adds its own with a
`Tempo.Event.Resolver`.

ISO 8601-2 has no notation for such a date, so Tempo writes it as a
selection `(name)e` and asks here for it, once per year, when a selection
or a recurrence such as `~o"R/../P1Y/FL(easter)eN"` is given its spans.

# `date`

```elixir
@spec date(String.t(), integer(), module()) ::
  {:ok, Date.t()} | {:error, Exception.t()}
```

The date of a named event in a year of the proleptic Gregorian calendar.

### Arguments

* `name` is an event `known/0` lists. An equinox or a solstice may name
  the zone whose date it takes after an `@`, an IANA zone or a `±HH:MM`
  offset (`"march-equinox@+09:00"`), the instant falling on another date
  there than in UTC.

* `year` is the Gregorian year.

* `calendar` is the calendar whose meridian a solar term is reckoned at:
  one of Calendrical's lunisolar calendars, or the Gregorian, the default,
  which reckons it at the Chinese meridian.

### Returns

* `{:ok, date}`, a `t:Date.t/0` in `Calendar.ISO`.

* `{:error, %Tempo.InvalidDateError{unit: :event}}` whose reason is
  `{:unknown_event, name}`, `{:no_instant, name}` for an `@` zone after an
  event that is no instant, `{:no_solar_terms, calendar}`,
  `:year_out_of_range` for a year `Astro` does not reach, or a resolver's
  own reason.

* `{:error, %Tempo.ZoneError{reason: :unknown}}` for a zone after an `@`
  that is none.

* `{:error, %ArgumentError{}}` for a name that is no string or a year
  that is no integer.

### Examples

    iex> Tempo.Event.date("easter", 2026)
    {:ok, ~D[2026-04-05]}

    iex> Tempo.Event.date("orthodox-easter", 2026)
    {:ok, ~D[2026-04-12]}

    iex> Tempo.Event.date("december-solstice", 2026)
    {:ok, ~D[2026-12-21]}

    iex> Tempo.Event.date("march-equinox@+09:00", 2002)
    {:ok, ~D[2002-03-21]}

    iex> Tempo.Event.date("qingming", 2026, Calendrical.Gregorian)
    {:ok, ~D[2026-04-05]}

    iex> {:error, %Tempo.InvalidDateError{reason: {:unknown_event, "brigadoon"}}} =
    ...>   Tempo.Event.date("brigadoon", 2026)

# `known`

```elixir
@spec known() :: [String.t()]
```

The names of the events `date/3` resolves: the built-ins and every name a
registered `Tempo.Event.Resolver` claims, sorted.

### Returns

* A sorted list of event names, each a string.

### Examples

    iex> "qingming" in Tempo.Event.known()
    true

    iex> "easter" in Tempo.Event.known()
    true

# `solar_term?`

```elixir
@spec solar_term?(String.t()) :: boolean()
```

Whether a name is one of the twenty-four solar terms.

### Arguments

* `name` is an event's name, a string.

### Returns

* `true` for one of the twenty-four, and `false` for any other name. A
  name that is no string raises an `ArgumentError`.

### Examples

    iex> Tempo.Event.solar_term?("qingming")
    true

    iex> Tempo.Event.solar_term?("easter")
    false

---

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