# `Calendrical.Islamic.UmmAlQura`

Implementation of the Saudi Arabian Umm al-Qura calendar.

The Umm al-Qura (أم القرى, "Mother of Towns" — a name for Mecca) calendar
is the official Hijri calendar of the Kingdom of Saudi Arabia and the
basis for date calculations published by the King Abdulaziz City for
Science and Technology (KACST). It differs from the purely tabular
Hijri calendars (`Calendrical.Islamic.Civil` and
`Calendrical.Islamic.Tbla`) in that the start of each month is
determined by an astronomical observation rule applied at Mecca rather
than by a fixed arithmetic cycle. Individual months may therefore
deviate from the tabular value by up to a day.

This module embeds the official month lengths published by KACST,
compiled from `priv/umm_al_qura_month_lengths.csv` into one bit per
month, and ICU's for the century after them, from
`priv/umm_al_qura_icu_month_lengths.csv`. Converting an Umm al-Qura date to the Gregorian calendar is an
O(1) lookup, and the reverse a binary search over the years, with no
floating-point arithmetic at runtime.

## Coverage

The tables cover **1 AH through 1600 AH** (19 July 622 CE through
25 November 2174 CE): KACST's published month lengths for 1 to 1500 AH,
the full range it publishes, and ICU4C's for 1501 to 1600 AH (from
`islamcal.cpp`, under the Unicode License), which take up from KACST's
without a gap. Run `mix calendrical.umm_al_qura.verify --kacst` to
compare the tables with KACST's current data.

Years before and after the tables are those of the arithmetic civil
calendar, `Calendrical.Islamic.Civil`, as ICU falls back to it outside
its own table. Civil 1 Muharram 1 AH and 1601 AH are the days the
tables begin and end on, so no year at either join is lengthened or
shortened. The year before 1 AH is year 0.

From 1300 AH this calendar is ICU's day for day. Before 1300 AH ICU
has no table and takes the civil calendar's months, where this one
keeps KACST's published months: 8,567 of the 15,588 months of 1 to
1299 AH begin on another day, most of them a day earlier here.

Before 1.4.0 this calendar used R.H. van Gent's tables. Those are an
astronomical reconstruction, reproduced by
`Calendrical.Islamic.UmmAlQura.Astronomical`, and differ from KACST's
official table in 695 months between 1356 and 1500 AH. The published
rule they apply is KACST's through 1450 AH; from 1451 AH KACST's
projected months begin a third of months a day later, as
`Calendrical.Islamic.UmmAlQura.Astronomical` explains.

Days begin at midnight by default. `date_at/2` maps an absolute instant to
the Hijri date under a chosen day-start convention — midnight, an 18:00
proxy, or true sunset (Maghrib) at Mecca.

## Reference

* KACST official month lengths,
  <https://umqserv.kacst.gov.sa/api/v1/DateConversion/GetHijriMonthLengths>.

* R.H. van Gent, "The Umm al-Qura Calendar of Saudi Arabia",
  <https://webspace.science.uu.nl/~gent0113/islam/ummalqura.htm>.

# `day`

```elixir
@type day() :: 1..30
```

# `month`

```elixir
@type month() :: 1..12
```

# `year`

```elixir
@type year() :: integer()
```

# `add`

Adds whole years, quarters or months to the fields of a naive
datetime, keeping its time of day: the `add/9` callback
[`CalendarInterval`](https://hexdocs.pm/calendar_interval) steps an
interval of a year or a month with. The date moves as `shift/6`
moves it, clamping the day into a shorter month.

### Arguments

* `year`, `month` and `day` are the date's fields in this calendar.

* `hour`, `minute`, `second` and `microsecond` are the time of day,
  returned unchanged.

* `precision` is `:year`, `:quarter` or `:month`.

* `step` is the number of years, quarters or months to add, which
  may be negative.

### Returns

* `{year, month, day, hour, minute, second, microsecond}`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year, month, day, 12, 30, 0, {0, 0}} =
    ...>   Calendrical.Islamic.UmmAlQura.add(date.year, date.month, date.day, 12, 30, 0, {0, 0}, :month, 1)
    iex> {year, month, day} == Calendrical.Islamic.UmmAlQura.shift(date.year, date.month, date.day, :months, 1, [])
    true

# `calendar_base`

Returns what this calendar's year is built of, `:month` or `:week`,
as its `info/0` states.

### Returns

* `:week` for a calendar whose year is built of weeks.

* `:month` otherwise.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.calendar_base() in [:month, :week]
    true

# `calendar_from_cldr_calendar_type`

Returns the calendar module whose CLDR calendar type is the one
given, whichever calendar is asked
(`Calendrical.calendar_from_cldr_calendar_type/1`).

### Arguments

* `calendar_type` is a CLDR calendar type as an atom or a string.

### Returns

* `{:ok, calendar_module}`, or

* `{:error, exception}` for a calendar type no calendar module has.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.calendar_from_cldr_calendar_type(:gregorian)
    {:ok, Calendrical.Gregorian}

    iex> {:error, %Localize.UnknownCalendarError{}} =
    ...>   Calendrical.Islamic.UmmAlQura.calendar_from_cldr_calendar_type(:not_a_calendar)

# `cardinal_day`

Returns the day a date is written with: the day of its
`written_date/3`.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The day of the date's `written_date/3`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar
  does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {_year, _month, written_day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.cardinal_day(date.year, date.month, date.day) == written_day
    true

# `cardinal_month`

Returns the CLDR month a month of the year names without a year
(`Calendrical.Month.cldr_month/2`).

### Arguments

* `month` is a month of this calendar.

### Returns

* The CLDR month the month is named in the year that holds
  1 January 2000, the month itself in the Hebrew calendar, whose
  names depend on the year, and the month itself where the
  reference year has no such month.

### Examples

    iex> {:ok, date} = Date.convert(~D[2000-01-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.cardinal_month(1) == Calendrical.Islamic.UmmAlQura.cldr_month(date.year, 1)
    true

# `cardinal_year`

Returns the year a date is written with: the year of its
`written_date/3`.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The year of the date's `written_date/3`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar
  does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {written_year, _month, _day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.cardinal_year(date.year, date.month, date.day) == written_year
    true

# `cldr_calendar_type`

Returns the CLDR calendar type whose data names this calendar's
months, days and quarters, as its `info/0` states.

### Returns

* A CLDR calendar type such as `:gregorian` or `:hebrew`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.cldr_calendar_type() == Calendrical.Islamic.UmmAlQura.info().cldr_calendar_type
    true

# `cldr_calendar_type`

Returns the CLDR calendar type whose data names a date's months and
days: the member in effect on the date in a composite calendar, and
this calendar's own otherwise (`Calendrical.Info.cldr_calendar_type/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* A CLDR calendar type.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> in_effect = Calendrical.Info.in_effect(Calendrical.Islamic.UmmAlQura, date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.cldr_calendar_type(date.year, date.month, date.day) == in_effect.cldr_calendar_type()
    true

# `cldr_month`

Returns the CLDR month of a month of a year
(`Calendrical.Month.cldr_month/3`).

### Arguments

* `year` and `month` are a month of this calendar.

### Returns

* A CLDR month number, or `{month, :leap}` where the month's name
  has a leap form, or

* `{:error, exception}` for a month the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> cldr_month = Calendrical.Islamic.UmmAlQura.cldr_month(date.year, date.month)
    iex> Calendrical.Islamic.UmmAlQura.written_month_from_cldr_month(date.year, cldr_month) ==
    ...>   Calendrical.Islamic.UmmAlQura.numeric_month(date.year, date.month, date.day)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.cldr_month(date.year, 99)

# `cyclic_year`

Returns the cyclic year of a date (`Calendrical.Era.cyclic_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The date's place in the sexagenary cycle, `1` to `60`, in an East
  Asian calendar, and its year in a calendar whose years run in no
  such cycle, or

* `{:error, %Calendrical.InvalidDateError{}}` for a year the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for no
  year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> cyclic_year = Calendrical.Islamic.UmmAlQura.cyclic_year(date.year, date.month, date.day)
    iex> cyclic_year in 1..60 or cyclic_year == date.year
    true

    iex> {:error, %Calendrical.MissingFieldsError{}} = Calendrical.Islamic.UmmAlQura.cyclic_year(nil, 1, 1)

# `date_at`

```elixir
@spec date_at(DateTime.t(), Keyword.t()) :: {:ok, Date.t()} | {:error, Exception.t()}
```

Returns the Umm al-Qura date in effect at a given instant, under a chosen
day-start convention.

The Islamic day traditionally begins at sunset, so after sunset the
Umm al-Qura date is already the following day. This function maps an
absolute instant to the Hijri date, choosing the day boundary with the
`:day_start` option. All boundaries are evaluated **at Mecca** — where the
Umm al-Qura calendar is defined — so the result is the official Hijri date
for that instant regardless of the observer's own time zone.

For the plain civil-day mapping (the calendar's default), convert a date
directly with `Date.convert/2` instead.

### Arguments

* `datetime` is a `t:DateTime.t/0` — an absolute instant. Its own time zone
  is used only to fix the instant; the day boundary is always taken at Mecca.

### Options

* `:day_start` selects the moment the Umm al-Qura day begins:

  * `:midnight` (the default) — the day begins at 00:00 Mecca time, i.e. the
    ordinary civil-day mapping.

  * `:evening` — the day begins at 18:00 Mecca time, the fixed-clock proxy
    for sunset used by many implementations.

  * `:sunset` — the day begins at true sunset (Maghrib) at Mecca, computed
    astronomically via `Astro`. This is upper-limb sunset, which differs by a
    minute or two from the centre-of-disk sunset that
    `Calendrical.Islamic.UmmAlQura.Astronomical` uses to start each month.

### Returns

* `{:ok, date}` — an Umm al-Qura `t:Date.t/0`.

* `{:error, %Calendrical.InvalidOptionValueError{}}` for an invalid
  `:day_start` or `:nightfall_angle`.

* `{:error, %Calendrical.UnsupportedDateRangeError{}}` for a date outside
  the range the calendar or the installed JPL ephemeris covers.

* `{:error, %Calendrical.NoDuskError{}}` where the sun does not set, or
  nightfall does not occur, at the location on that day.

### Examples

    # Morning at Mecca: every convention agrees.
    iex> Calendrical.Islamic.UmmAlQura.date_at(~U[2025-03-01 06:00:00Z])
    {:ok, ~D[1446-09-01 Calendrical.Islamic.UmmAlQura]}

    # After sunset the evening convention has rolled to the next Hijri day.
    iex> Calendrical.Islamic.UmmAlQura.date_at(~U[2025-03-01 16:00:00Z], day_start: :evening)
    {:ok, ~D[1446-09-02 Calendrical.Islamic.UmmAlQura]}

# `date_from_cardinal_date`

Returns the date of this calendar that written figures name
(`date_from_written_date/3`), as fields.

### Arguments

* `year`, `month` and `day` are the figures a date is written with,
  as `written_date/3` returns them.

### Returns

* `{year, month, day}`, the date of this calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` where the figures name no date.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year, month, day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.date_from_cardinal_date(year, month, day) == {date.year, date.month, date.day}
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.date_from_cardinal_date(date.year, 0, 1)

# `date_from_day_of_year`

Returns the date of a day of a year, counted from the year's first
day.

### Arguments

* `year` is a year of this calendar.

* `day_of_year` is the day of the year, counted from 1.

### Returns

* A `t:Date.t/0` of this calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` for a day the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> day_of_year = Calendrical.Islamic.UmmAlQura.day_of_year(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.date_from_day_of_year(date.year, day_of_year) == date
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.date_from_day_of_year(date.year, 1000)

# `date_from_iso_days`

```elixir
@spec date_from_iso_days(integer()) :: {year(), month(), day()}
```

Returns the Umm al-Qura `{year, month, day}` for the given ISO day
number, by the civil calendar outside the published tables.

### Arguments

* `iso_days` is the number of days since the ISO epoch.

### Returns

* A `{year, month, day}` tuple.

### Examples

    iex> iso_days = Date.to_gregorian_days(~D[2025-03-01])
    iex> Calendrical.Islamic.UmmAlQura.date_from_iso_days(iso_days)
    {1446, 9, 1}

# `date_from_week_date`

Returns the date of a day of a week of a week-year
(`Calendrical.Week.date_from_week_date/4`).

### Arguments

* `week_year` is a week-year of this calendar.

* `week` is a week of the week-year.

* `day` is the day of the week, numbered from 1 for the day the
  calendar's weeks begin on.

### Returns

* A `t:Date.t/0` of this calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` where the week has no such day.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {week_year, week, day} = Calendrical.Islamic.UmmAlQura.week_date_from_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.date_from_week_date(week_year, week, day) == date
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.date_from_week_date(date.year, 1, 8)

# `date_from_written_date`

Returns the date of this calendar that written figures name: the
inverse of `written_date/3`, the fields themselves where they are a
date.

### Arguments

* `year`, `month` and `day` are the figures a date is written with,
  as `written_date/3` returns them.

### Returns

* `{:ok, {year, month, day}}`, the date of this calendar, or

* `{:error, :invalid_date}` where the figures name no date.

The reason is an atom, not an exception: Localize's date parser reads
it, as `c:Calendrical.date_from_written_date/3` sets out.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year, month, day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.date_from_written_date(year, month, day) == {:ok, {date.year, date.month, date.day}}
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.date_from_written_date(date.year, 0, 1)
    {:error, :invalid_date}

# `date_to_iso_days`

```elixir
@spec date_to_iso_days(year(), month(), day()) :: integer()
```

Returns the number of ISO days for the given Umm al-Qura
`year`, `month`, and `day`, by the civil calendar outside the
published tables.

### Arguments

* `year` is the Hijri year.

* `month` is the Hijri month.

* `day` is the day of the month.

### Returns

* The number of days since the ISO epoch, as an integer.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.date_to_iso_days(1446, 9, 1) ==
    ...>   Date.to_gregorian_days(~D[2025-03-01])
    true

# `dates_in_gregorian_year`

Returns the dates of this calendar, earliest first, whose month and
day are those given and that fall in a Gregorian year.

### Arguments

* `gregorian_year` is the Gregorian year to search within.

* `month` and `day` are a month and a day of this calendar.

### Returns

* A list of zero, one or two `t:Date.t/0` of this calendar, earliest
  first, since this calendar's years and the Gregorian years drift.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> date in Calendrical.Islamic.UmmAlQura.dates_in_gregorian_year(2024, date.month, date.day)
    true

# `day_numbers`

Returns the days a month of a year has, as runs of their numbers
(`Calendrical.Month.day_numbers/3`).

### Arguments

* `year` and `month` are a month of this calendar.

### Returns

* A list of ranges: one from 1 in every month of every calendar but
  a composite, whose month a change of calendar falls in has the
  days that are left, and `[]` for a month the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.day_numbers(date.year, date.month) ==
    ...>   [1..Calendrical.Islamic.UmmAlQura.days_in_month(date.year, date.month)//1]
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.day_numbers(date.year, 99)
    []

# `day_of_era`

Returns the day of era and era of a date (`Calendrical.Era.day_of_era/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{day_of_era, era}`, where the day of the era counts from the
  era's first day, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for a
  missing field.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {day_of_era, era} = Calendrical.Islamic.UmmAlQura.day_of_era(date.year, date.month, date.day)
    iex> {_year_of_era, year_era} = Calendrical.Islamic.UmmAlQura.year_of_era(date.year, date.month, date.day)
    iex> day_of_era >= 1 and era == year_era
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.day_of_era(date.year, date.month, 0)

# `day_of_week`

Returns the day of the week of a date (`Calendrical.Week.day_of_week/5`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

* `starting_on` is `:default` for the day this calendar's weeks
  begin on, or the name of a weekday, `:monday` to `:sunday`.

### Returns

* `{day_of_week, 1, 7}`, the day numbered from the day the week
  begins on, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for a
  missing field.

### Examples

    # 1 June 2024 is a Saturday
    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.day_of_week(date.year, date.month, date.day, :monday)
    {6, 1, 7}

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.day_of_week(date.year, date.month, 0, :monday)

# `day_of_year`

Returns the day of the year of a date (`Calendrical.Period.day_of_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The day of the year, counted from 1 for its first day, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for a
  missing field.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> first_day = Calendrical.Islamic.UmmAlQura.year(date.year).first
    iex> Calendrical.Islamic.UmmAlQura.day_of_year(date.year, date.month, date.day) == Date.diff(date, first_day) + 1
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.day_of_year(date.year, date.month, 0)

# `days_in_month`

Returns the number of days in a month without a year
(`Calendrical.Month.days_in_month/2`).

### Arguments

* `month` is a month of this calendar.

### Returns

* The number of days where the month has as many in every year, or

* `{:ambiguous, lengths}` where its length depends on the year, the
  lengths a range or, where they are not consecutive, a list, or

* `{:error, %Calendrical.NotDefinedError{}}` for a month the calendar has in no year, or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, where
  the month is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {fewest, most} = Calendrical.Islamic.UmmAlQura.days_in_month_bounds(date.month)
    iex> case Calendrical.Islamic.UmmAlQura.days_in_month(date.month) do
    ...>   days when is_integer(days) -> fewest == days and most == days
    ...>   {:ambiguous, lengths} -> Enum.min(lengths) == fewest and Enum.max(lengths) == most
    ...> end
    true

    iex> {:error, %Calendrical.NotDefinedError{}} = Calendrical.Islamic.UmmAlQura.days_in_month(99)

# `days_in_month`

```elixir
@spec days_in_month(Calendar.year(), Calendar.month()) ::
  Calendar.day() | {:error, Exception.t()}
@spec days_in_month(year(), month()) :: 29..30 | {:error, Exception.t()}
```

Returns the number of days in the given Hijri `year` and `month`.
Months are 29 or 30 days as determined by the published Umm al-Qura
tables, or by the civil calendar outside them.

### Arguments

* `year` is the Hijri year.

* `month` is the Hijri month, from `1` to `12`.

### Returns

* The number of days in the month, `29` or `30`, or

* `{:error, %Calendrical.InvalidMonthError{}}` for a month the year
  does not have, or

* `{:error, %Calendrical.MissingFieldsError{}}` where the year or the
  month is `nil`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.days_in_month(1446, 9)
    29

# `days_in_month_bounds`

Returns the fewest and the most days a month has in any year
(`Calendrical.Month.days_in_month_bounds/2`).

### Arguments

* `month` is a month of this calendar.

### Returns

* `{fewest, most}`, or

* `{:error, exception}` for a month the calendar has in no year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {fewest, most} = Calendrical.Islamic.UmmAlQura.days_in_month_bounds(date.month)
    iex> Calendrical.Islamic.UmmAlQura.days_in_month(date.year, date.month) in fewest..most
    true

    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.days_in_month_bounds(99)

# `days_in_week`

Returns the number of days in a week.

### Returns

* `7`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.days_in_week()
    7

# `days_in_year`

Returns the number of days in a year (`Calendrical.Period.days_in_year/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* The number of days, or

* `{:error, %Calendrical.InvalidDateError{}}` for a year the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for no
  year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.days_in_year(date.year) == Enum.count(Calendrical.Islamic.UmmAlQura.year(date.year))
    true

    iex> {:error, %Calendrical.MissingFieldsError{}} = Calendrical.Islamic.UmmAlQura.days_in_year(nil)

# `diff`

Returns the number of whole units between two dates, counted
positionally.

### Arguments

* `from` and `to` are dates of this calendar as `{year, month, day}`
  tuples.

* `date_part` is one of `:years`, `:quarters`, `:months`, `:weeks`
  or `:days`.

### Returns

* The largest number of `date_part`s that can be added to `from`
  without passing `to`, negative where `to` is before `from`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a `from` or `to`
  the calendar does not have, `{:error, %Calendrical.MissingFieldsError{}}`
  for one missing a field, or `{:error, %Calendrical.InvalidPartError{}}`
  for a `date_part` other than the five.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> from = {date.year, date.month, date.day}
    iex> Calendrical.Islamic.UmmAlQura.diff(from, {date.year + 1, date.month, date.day}, :years)
    1

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> later = Date.add(date, 10)
    iex> Calendrical.Islamic.UmmAlQura.diff({later.year, later.month, later.day}, {date.year, date.month, date.day}, :days)
    -10

# `epoch`

Returns the epoch of this calendar: the ISO day number of
its first day.

### Returns

* The epoch as an integer number of days since the ISO epoch.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.epoch() |> is_integer()
    true

# `era_calendar_type`

Returns the CLDR calendar type that names this calendar's eras, as
its `info/0` states.

### Returns

* A CLDR calendar type such as `:gregorian` or `:japanese`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.era_calendar_type() == Calendrical.Islamic.UmmAlQura.info().era_calendar_type
    true

# `extended_year`

Returns the extended year of a date (`Calendrical.Era.extended_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The year numbered without a gap at 0, so that in a calendar with
  no year 0 the year before 1 is 0, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have, or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for no
  year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.extended_year(date.year, date.month, date.day) == date.year
    true

    iex> {:error, %Calendrical.MissingFieldsError{}} = Calendrical.Islamic.UmmAlQura.extended_year(nil, 1, 1)

# `first_day_of_month`

```elixir
@spec first_day_of_month(year(), month()) :: {:ok, Date.t()} | {:error, Exception.t()}
```

Returns the Gregorian `t:Calendar.date/0` of the first day of the given
Hijri month according to the official Umm al-Qura tables.

### Arguments

* `hijri_year` is the Hijri year.

* `hijri_month` is the Hijri month, from `1` to `12`.

### Returns

* `{:ok, date}` where `date` is the Gregorian `t:Date.t/0` of the
  first day of the month.

* `{:error, %Calendrical.IslamicYearOutOfRangeError{}}` if the
  requested month falls outside the embedded data range, where the
  calendar's months are the civil calendar's.

* `{:error, %Calendrical.InvalidMonthError{}}` for a month that is
  not `1` to `12`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.first_day_of_month(1446, 9)
    {:ok, ~D[2025-03-01]}

    iex> {:error, %Calendrical.IslamicYearOutOfRangeError{}} =
    ...>   Calendrical.Islamic.UmmAlQura.first_day_of_month(1700, 1)

    iex> {:error, %Calendrical.InvalidMonthError{year: 1446, month: 13}} =
    ...>   Calendrical.Islamic.UmmAlQura.first_day_of_month(1446, 13)

# `info`

Returns the static facts about this calendar, as
`t:Calendrical.Info.t/0`.

### Returns

* A `t:Calendrical.Info.t/0` describing this calendar.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.info().calendar
    Calendrical.Islamic.UmmAlQura

# `iso_week_of_year`

Returns the ISO 8601 week-year and week of the day a date names
(`Calendrical.Week.iso_week_of_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{week_year, week}` of ISO 8601, or

* `{:error, exception}` for a date the calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.iso_week_of_year(date.year, date.month, date.day)
    {2024, 22}

# `leap_month`

Returns the position of a year's leap month, or `nil` where the
year has none.

### Arguments

* `year` is a year of this calendar.

### Returns

* The leap month's position in the year, or

* `nil` where the year has no leap month, as for anything but an
  integer year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> leap_month = Calendrical.Islamic.UmmAlQura.leap_month(date.year)
    iex> is_nil(leap_month) or leap_month in 1..Calendrical.Islamic.UmmAlQura.months_in_year(date.year)
    true

# `leap_year?`

Returns whether the given Hijri `year` is a leap year (355 days).

### Arguments

* `year` is the Hijri year.

### Returns

* `true` if the year has 355 days, otherwise `false`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.leap_year?(1447)
    true

    iex> Calendrical.Islamic.UmmAlQura.leap_year?(1446)
    false

# `lunar_month_of_year`

Returns the traditional month at a position in a year
(`Calendrical.Month.traditional_month/3`), or an error for a place
the year does not have.

### Arguments

* `year` and `month` are a month of this calendar.

### Returns

* The month's traditional number, or `{month, :leap}` for a leap
  month, or

* `{:error, %Calendrical.InvalidMonthError{}}` for a month the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.lunar_month_of_year(date.year, date.month) ==
    ...>   Calendrical.Islamic.UmmAlQura.traditional_month(date.year, date.month)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.lunar_month_of_year(date.year, 99)

# `max_year`

```elixir
@spec max_year() :: 1600
```

Returns the last Hijri year covered by the embedded Umm al-Qura
tables: KACST's to 1500 AH, then ICU's.

### Returns

* The last Hijri year of the tables, as an integer.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.max_year()
    1600

# `min_year`

```elixir
@spec min_year() :: 1
```

Returns the first Hijri year covered by the embedded Umm al-Qura
tables.

### Returns

* The first Hijri year of the tables, as an integer.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.min_year()
    1

# `month`

Returns the days of a month of a year (`Calendrical.Period.month/3`).

### Arguments

* `year` and `month` are a month of this calendar.

### Returns

* A `t:Date.Range.t/0`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a month the year does not have, or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for a
  missing year or month.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> date in Calendrical.Islamic.UmmAlQura.month(date.year, date.month)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.month(date.year, 99)

# `month_from_traditional`

Returns the position of a traditional month in a year
(`Calendrical.Month.month_from_traditional/3`).

### Arguments

* `year` is a year of this calendar.

* `traditional_month` is a month's traditional number, or
  `{month, :leap}` for a leap month.

### Returns

* The month's position in the year, or

* `{:error, exception}` where the year has no such month.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> traditional_month = Calendrical.Islamic.UmmAlQura.traditional_month(date.year, date.month)
    iex> Calendrical.Islamic.UmmAlQura.month_from_traditional(date.year, traditional_month) == date.month
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.month_from_traditional(date.year, 99)

# `month_numbers`

Returns the months a year has, as runs of their numbers
(`Calendrical.Month.month_numbers/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* A list of ranges: one from 1 in every year of every calendar but a
  composite, whose year a change of calendar falls in has the months
  that are left, and `[]` for a year the calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.month_numbers(date.year) == [1..Calendrical.Islamic.UmmAlQura.months_in_year(date.year)//1]
    true

# `month_of_year`

Returns the CLDR month of a month of a year: the index of its name
in this calendar's CLDR data, with `{month, :leap}` where the name
has a leap form (`Calendrical.Month.cldr_month/3`).

### Arguments

* `year`, `month` and `day` are a date of this calendar. The year
  and the day may be `nil`: a month's name needs only the month.

### Returns

* A CLDR month number, or `{month, :leap}`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a day the month does not have, or

* `{:error, exception}` for a month the year does not have, or a
  `Calendrical.MissingFieldsError` where the month is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.month_of_year(date.year, date.month, date.day) == Calendrical.Islamic.UmmAlQura.cldr_month(date.year, date.month)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.month_of_year(date.year, date.month, 0)

# `months_in_leap_year`

Returns the number of months in a leap year: the most months a year
of this calendar has.

### Returns

* A positive integer.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.months_in_leap_year() >= Calendrical.Islamic.UmmAlQura.months_in_ordinary_year()
    true

# `months_in_ordinary_year`

Returns the number of months in an ordinary year: the fewest months
a year of this calendar has.

### Returns

* A positive integer.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.months_in_ordinary_year() <= Calendrical.Islamic.UmmAlQura.months_in_leap_year()
    true

# `months_in_year`

Returns the number of months in a year without a year: the count
where every year has as many, `{:ambiguous, range}` where a leap
year has more, and `{:error, %Calendrical.NotDefinedError{}}` for a composite calendar
(`Calendrical.Info.months_in_year/1`).

### Returns

* The number of months where every year has as many, or

* `{:ambiguous, fewest..most}` where a leap year has more, or

* `{:error, %Calendrical.NotDefinedError{}}` for a composite calendar, whose bounds
  `months_in_year_bounds/0` gives.

### Examples

    iex> case Calendrical.Islamic.UmmAlQura.months_in_year() do
    ...>   months when is_integer(months) -> months == Calendrical.Islamic.UmmAlQura.months_in_leap_year()
    ...>   {:ambiguous, fewest..most//1} -> {fewest, most} == Calendrical.Islamic.UmmAlQura.info().months_in_year
    ...>   {:error, %Calendrical.NotDefinedError{}} -> is_list(Calendrical.Islamic.UmmAlQura.info().members)
    ...> end
    true

# `months_in_year`

Returns the number of months in a
given `year`.

### Arguments

* `year` is the year in this calendar.

### Returns

* The number of months in the year, as a positive integer, or

* `{:error, %Calendrical.MissingFieldsError{}}` where `year` is `nil`, or

* `{:error, %Calendrical.InvalidDateError{}}` where `year` is no integer.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.months_in_year(date.year) >= date.month
    true

# `months_in_year_bounds`

Returns the fewest and the most months a year has
(`Calendrical.Month.months_in_year_bounds/1`).

### Returns

* `{fewest, most}`, which in a composite calendar counts the months
  left in a year a change of calendar falls in.

### Examples

    iex> {fewest, most} = Calendrical.Islamic.UmmAlQura.months_in_year_bounds()
    iex> fewest <= Calendrical.Islamic.UmmAlQura.months_in_ordinary_year() and
    ...>   most >= Calendrical.Islamic.UmmAlQura.months_in_leap_year()
    true

# `naive_datetime_from_iso_days`

Converts ISO days and a day fraction to a naive datetime of this
calendar, as `c:Calendar.naive_datetime_from_iso_days/1` asks.

### Arguments

* `iso_days` is `{days, {parts_in_day, parts_per_day}}`, a day and a
  fraction of it.

### Returns

* `{year, month, day, hour, minute, second, microsecond}` of this
  calendar.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year, month, day, 12, 0, 0, {0, 6}} =
    ...>   Calendrical.Islamic.UmmAlQura.naive_datetime_from_iso_days({739403, {43200000000, 86400000000}})
    iex> {year, month, day} == {date.year, date.month, date.day}
    true

# `naive_datetime_to_iso_days`

Converts a naive datetime of this calendar to ISO days and a day
fraction, as `c:Calendar.naive_datetime_to_iso_days/7` asks.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

* `hour`, `minute`, `second` and `microsecond` are a time of day,
  the microsecond as `{microseconds, precision}`.

### Returns

* `{iso_days, {parts_in_day, parts_per_day}}`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.naive_datetime_to_iso_days(date.year, date.month, date.day, 12, 0, 0, {0, 6})
    {739403, {43200000000, 86400000000}}

# `named_month`

Returns the days of a named month in a year
(`Calendrical.Month.named_month/3`).

### Arguments

* `year` is a year of this calendar.

* `named_month` is the CLDR month that names the month.

### Returns

* A list of `t:Date.Range.t/0`, one for each counted month that
  carries the name, earliest first, and `[]` where none does.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> cldr_month = Calendrical.Islamic.UmmAlQura.cldr_month(date.year, date.month)
    iex> Calendrical.Islamic.UmmAlQura.named_month(date.year, cldr_month) |> Enum.any?(&(date in &1))
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.named_month(date.year, 99)
    []

# `numeric_month`

Returns the number a date's month is written with in figures: the
month of its `written_date/3`.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The month of the date's `written_date/3`: a month number, or
  `{month, :leap}` for a leap month of a lunisolar calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar
  does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {_year, written_month, _day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.numeric_month(date.year, date.month, date.day) == written_month
    true

# `ordinal_month_from_traditional`

Returns the position in a year of a traditional month
(`Calendrical.Month.month_from_traditional/3`), as `{:ok, month}`.

### Arguments

* `year` is a year of this calendar.

* `traditional_month` is a month's traditional number, or
  `{month, :leap}` for a leap month.

### Returns

* `{:ok, month}`, the month's position in the year, or

* `{:error, %Calendrical.InvalidMonthError{}}` for a month or a leap
  month the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> traditional_month = Calendrical.Islamic.UmmAlQura.traditional_month(date.year, date.month)
    iex> Calendrical.Islamic.UmmAlQura.ordinal_month_from_traditional(date.year, traditional_month) == {:ok, date.month}
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.ordinal_month_from_traditional(date.year, 99)

# `parse_date`

Parses a date written in this calendar's own notation.

### Arguments

* `string` is a date written `YYYY-MM-DD`, with a leading `-` for a
  year before 1, or, in a calendar of weeks, `YYYY-Www-D`.

### Returns

* `{:ok, {year, month, day}}`, or

* `{:error, :invalid_format}` where the text is not in that form or
  its fields are not digits, or

* `{:error, :invalid_date}` where the text names no date of this
  calendar.

The reason is an atom, not an exception, because `c:Calendar.parse_date/1`
requires one: `Date.from_iso8601/2` reads it.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.parse_date(Date.to_string(date)) == {:ok, {date.year, date.month, date.day}}
    true

    iex> Calendrical.Islamic.UmmAlQura.parse_date("not a date")
    {:error, :invalid_format}

# `parse_naive_datetime`

Parses a naive datetime written in this calendar's own notation.

### Arguments

* `string` is a date as `parse_date/1` reads it, then `T` or a
  space and a time of day.

### Returns

* `{:ok, {year, month, day, hour, minute, second, microsecond}}`, or

* `{:error, reason}`, such as `:invalid_format` or `:invalid_date`,
  where the text is no such datetime.

The reason is an atom, not an exception, because
`c:Calendar.parse_naive_datetime/1` requires one:
`NaiveDateTime.from_iso8601/2` reads it.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.parse_naive_datetime(Date.to_string(date) <> "T12:00:00") ==
    ...>   {:ok, {date.year, date.month, date.day, 12, 0, 0, {0, 0}}}
    true

    iex> Calendrical.Islamic.UmmAlQura.parse_naive_datetime("2024-06-01")
    {:error, :invalid_format}

# `parse_utc_datetime`

Parses a UTC datetime written in this calendar's own notation.

### Arguments

* `string` is a date as `parse_date/1` reads it, then `T` or a
  space, a time of day and an offset from UTC, `Z` or `±HH:MM`.

### Returns

* `{:ok, {year, month, day, hour, minute, second, microsecond}, offset}`,
  the datetime in UTC and the offset in seconds it was written with,
  or

* `{:error, reason}`, such as `:invalid_format`, `:invalid_date` or
  `:missing_offset`, where the text is no such datetime.

The reason is an atom, not an exception, because
`c:Calendar.parse_utc_datetime/1` requires one:
`DateTime.from_iso8601/2` reads it.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.parse_utc_datetime(Date.to_string(date) <> "T12:00:00Z") ==
    ...>   {:ok, {date.year, date.month, date.day, 12, 0, 0, {0, 0}}, 0}
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.parse_utc_datetime(Date.to_string(date) <> "T12:00:00")
    {:error, :missing_offset}

# `parsing_calendar`

Returns the calendar a date written for this calendar is parsed in,
as its `info/0` states.

### Returns

* A calendar module.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.parsing_calendar() == Calendrical.Islamic.UmmAlQura.info().parsing_calendar
    true

# `parsing_calendars`

Returns the calendars a date written for this calendar may be
written in: the members of a composite calendar, and this calendar
alone otherwise (`Calendrical.Info.parsing_calendars/1`).

### Returns

* A non-empty list of calendar modules, the members of a composite
  calendar in the order they take effect.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> in_effect = Calendrical.Info.in_effect(Calendrical.Islamic.UmmAlQura, date.year, date.month, date.day)
    iex> in_effect in Calendrical.Islamic.UmmAlQura.parsing_calendars()
    true

# `periods_in_year`

Returns the number of periods in a year: its months.

### Arguments

* `year` is a year of this calendar.

### Returns

* The number of months in the year, as `months_in_year/1` returns
  it.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.periods_in_year(date.year) == Calendrical.Islamic.UmmAlQura.months_in_year(date.year)
    true

# `quadrimester`

Returns the days of a quadrimester of a year
(`Calendrical.Period.quadrimester/3`).

### Arguments

* `year` is a year of this calendar.

* `quadrimester` is the quadrimester, `1` to `3`.

### Returns

* A `t:Date.Range.t/0`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a quadrimester or a year the
  calendar does not have, or

* `{:error, %Calendrical.MissingFieldsError{}}` where the year or the
  quadrimester is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.quadrimester(date.year, 1).first == Calendrical.Islamic.UmmAlQura.year(date.year).first
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.quadrimester(date.year, 4)

# `quarter`

Returns the days of a quarter of a year (`Calendrical.Period.quarter/3`).

### Arguments

* `year` is a year of this calendar.

* `quarter` is the quarter, `1` to `4`.

### Returns

* A `t:Date.Range.t/0`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a quarter or a year the calendar
  does not have, or

* `{:error, %Calendrical.MissingFieldsError{}}` where the year or the
  quarter is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> quarter = Calendrical.Islamic.UmmAlQura.quarter_of_year(date.year, date.month, date.day)
    iex> date in Calendrical.Islamic.UmmAlQura.quarter(date.year, quarter)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.quarter(date.year, 5)

# `quarter_of_year`

Returns the quarter of the year a date falls in
(`Calendrical.Period.quarter_of_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The quarter, `1` to `4`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for a
  missing year or month.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.quarter_of_year(date.year, date.month, date.day) in 1..4
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.quarter_of_year(date.year, date.month, 0)

# `related_gregorian_year`

Returns the related Gregorian year of a date
(`Calendrical.Era.related_gregorian_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* The Gregorian year the date's calendar year begins in, or

* `{:error, %Calendrical.InvalidDateError{}}` for a year the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for no
  year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:ok, first_day} = Date.convert(Calendrical.Islamic.UmmAlQura.year(date.year).first, Calendrical.Gregorian)
    iex> Calendrical.Islamic.UmmAlQura.related_gregorian_year(date.year, date.month, date.day) == first_day.year
    true

# `semester`

Returns the days of a semester of a year (`Calendrical.Period.semester/3`).

### Arguments

* `year` is a year of this calendar.

* `semester` is the semester, `1` or `2`.

### Returns

* A `t:Date.Range.t/0`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a semester or a year the calendar
  does not have, or

* `{:error, %Calendrical.MissingFieldsError{}}` where the year or the
  semester is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.semester(date.year, 1).first == Calendrical.Islamic.UmmAlQura.year(date.year).first
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.semester(date.year, 3)

# `shift`

Returns the date a number of years, quarters, months, weeks or days
on from a date of this calendar, by position, with the traditional
month kept across years and a day the resulting month lacks clamped
to its last day unless `clamp: false` (`Calendrical.Shift.shift/7`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

* `date_part` is one of `:years`, `:quarters`, `:months`, `:weeks`
  or `:days`.

* `increment` is the number of units, which may be negative.

* `options` is a keyword list of options.

### Options

* `:clamp` is whether a day the resulting month lacks becomes its
  last day. The default is `true`.

### Returns

* `{year, month, day}` of this calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` where `year`, `month` and
  `day` are no date of this calendar, or

* `{:error, %Calendrical.MissingFieldsError{}}` where a field is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.shift(date.year, date.month, date.day, :days, 0)
    {date.year, date.month, date.day}

# `shift_date`

Shifts a date by a duration: its years and months together, as
`shift/6` adds months, and then its weeks and days.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

* `duration` is a `t:Duration.t/0`.

### Returns

* `{year, month, day}` of this calendar.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year, month, day} = Calendrical.Islamic.UmmAlQura.shift_date(date.year, date.month, date.day, Duration.new!(day: 7))
    iex> Date.new!(year, month, day, Calendrical.Islamic.UmmAlQura) == Date.add(date, 7)
    true

# `shift_naive_datetime`

Shifts a naive datetime by a duration: its date as `shift_date/4`
shifts it, and its time as `Calendar.ISO` does.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

* `hour`, `minute`, `second` and `microsecond` are a time of day,
  the microsecond as `{microseconds, precision}`.

* `duration` is a `t:Duration.t/0`.

### Returns

* `{year, month, day, hour, minute, second, microsecond}` of this
  calendar.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> next_day = Date.add(date, 1)
    iex> Calendrical.Islamic.UmmAlQura.shift_naive_datetime(date.year, date.month, date.day, 23, 0, 0, {0, 0}, Duration.new!(hour: 2)) ==
    ...>   {next_day.year, next_day.month, next_day.day, 1, 0, 0, {0, 0}}
    true

# `shift_time`

Shifts a time by a duration, as `Calendar.ISO` does.

### Arguments

* `hour`, `minute`, `second` and `microsecond` are a time of day,
  the microsecond as `{microseconds, precision}`.

* `duration` is a `t:Duration.t/0` of time units.

### Returns

* `{hour, minute, second, microsecond}`, wrapped around midnight.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.shift_time(23, 0, 0, {0, 0}, Duration.new!(hour: 2))
    {1, 0, 0, {0, 0}}

# `solar_term`

Returns the day of a solar term of a Gregorian year, reckoned at the
place this calendar's `info/0` names, or at the Chinese calendar's
meridian, the traditional reference, where it names none.

### Arguments

* `index` is the solar term's number, `1` (lichun, 315° of solar
  longitude) to `24`, every 15° on.

* `gregorian_year` is a Gregorian year.

### Returns

* `{:ok, date}`, a `t:Date.t/0` in `Calendrical.Gregorian`, or

* `{:error, %Calendrical.InvalidSolarTermError{}}` where `index` is not
  `1` to `24`.

### Examples

    # Qingming, the fifth solar term
    iex> Calendrical.Islamic.UmmAlQura.solar_term(5, 2025)
    {:ok, ~D[2025-04-04 Calendrical.Gregorian]}

    iex> Calendrical.Islamic.UmmAlQura.solar_term(25, 2025)
    {:error, %Calendrical.InvalidSolarTermError{index: 25}}

# `traditional_leap_month`

Returns the traditional number of the month a year's leap month
follows, or `nil` (`Calendrical.Month.traditional_leap_month/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* The traditional number of the month the leap month follows, or

* `nil` where the year has no leap month.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> is_nil(Calendrical.Islamic.UmmAlQura.traditional_leap_month(date.year)) ==
    ...>   is_nil(Calendrical.Islamic.UmmAlQura.leap_month(date.year))
    true

# `traditional_month`

Returns a month of a year as this calendar names it
(`Calendrical.Month.traditional_month/3`).

### Arguments

* `year` and `month` are a month of this calendar.

### Returns

* The month's traditional number, or `{month, :leap}` for a leap
  month, or

* `{:error, exception}` for a month the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.traditional_month(date.year, date.month) ==
    ...>   Enum.at(Calendrical.Islamic.UmmAlQura.traditional_months(date.year), date.month - 1)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.traditional_month(date.year, 99)

# `traditional_months`

Returns a year's months in order, named traditionally
(`Calendrical.Month.traditional_months/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* A list of traditional months, the nth naming the year's nth month,
  with `{month, :leap}` for a leap month, and `[]` for a year the
  calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> length(Calendrical.Islamic.UmmAlQura.traditional_months(date.year)) ==
    ...>   Calendrical.Islamic.UmmAlQura.months_in_year(date.year)
    true

# `valid_date?`

Determines if the given Umm al-Qura date is valid.

A date is valid if its `month` is in `1..12` and its `day` is between
1 and the number of days in that month: by the published tables for
1 AH to 1500 AH, and by the civil calendar for other years.

### Arguments

* `year` is the Hijri year.

* `month` is the Hijri month.

* `day` is the day of the month.

### Returns

* `true` if the date is valid, otherwise `false`.

### Examples

    iex> Calendrical.Islamic.UmmAlQura.valid_date?(1446, 9, 1)
    true

    iex> Calendrical.Islamic.UmmAlQura.valid_date?(1446, 13, 1)
    false

# `week`

Returns the seven days of a week of a year (`Calendrical.Week.week/3`).

### Arguments

* `year` is a year of this calendar.

* `week` is a week of the year.

### Returns

* A `t:Date.Range.t/0` of the week's seven days, which may begin in
  the year before or end in the year after, or

* `{:error, %Calendrical.InvalidDateError{}}` for a week the year does not have, or

* `{:error, %Calendrical.MissingFieldsError{}}` where the year or the
  week is `nil`.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {week_year, week} = Calendrical.Islamic.UmmAlQura.week_of_year(date.year, date.month, date.day)
    iex> days = Calendrical.Islamic.UmmAlQura.week(week_year, week)
    iex> {Enum.count(days), date in days}
    {7, true}

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.week(date.year, 0)

# `week_date_from_date`

Returns the week-year, the week and the day of the week of a date
(`Calendrical.Week.week_date_from_date/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{week_year, week, day_of_week}`, the day numbered from the day
  the calendar's weeks begin on, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {week_year, week, day} = Calendrical.Islamic.UmmAlQura.week_date_from_date(date.year, date.month, date.day)
    iex> {week_year, week} == Calendrical.Islamic.UmmAlQura.week_of_year(date.year, date.month, date.day) and day in 1..7
    true

# `week_of_month`

Returns the month and the week of the month a date is in
(`Calendrical.Week.week_of_month/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{month, week}`, where the month is the one before or after where
  the date falls in that month's last or first week, or

* `{:error, exception}` for a date the calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {month, week} = Calendrical.Islamic.UmmAlQura.week_of_month(date.year, date.month, date.day)
    iex> month in (date.month - 1)..(date.month + 1) and week >= 1
    true

# `week_of_year`

Returns the week-year and the week of the year a date is in
(`Calendrical.Week.week_of_year/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{week_year, week}`, where the week-year is the year before or
  after where the date falls in that year's last or first week, or

* `{:error, exception}` for a date the calendar does not have: a
  `Calendrical.MissingFieldsError` for a date missing a field, and a
  `Calendrical.InvalidDateError` otherwise.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {week_year, week} = Calendrical.Islamic.UmmAlQura.week_of_year(date.year, date.month, date.day)
    iex> date in Calendrical.Islamic.UmmAlQura.week(week_year, week)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.week_of_year(date.year, date.month, 0)

# `weeks_in_week_year`

Returns the number of weeks in a week-year
(`Calendrical.Week.weeks_in_week_year/2`).

### Arguments

* `week_year` is a week-year of this calendar.

### Returns

* The number of weeks, or

* `{:error, %Calendrical.InvalidDateError{}}` for a year the calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {week_year, week, _day} = Calendrical.Islamic.UmmAlQura.week_date_from_date(date.year, date.month, date.day)
    iex> week <= Calendrical.Islamic.UmmAlQura.weeks_in_week_year(week_year)
    true

# `weeks_in_year`

Returns the number of weeks in a year (`Calendrical.Week.weeks_in_year/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* The number of weeks, or

* `{:error, exception}` for a year the calendar does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {week_year, week} = Calendrical.Islamic.UmmAlQura.week_of_year(date.year, date.month, date.day)
    iex> week <= Calendrical.Islamic.UmmAlQura.weeks_in_year(week_year)
    true

# `weeks_of_month`

Returns the weeks of a month of a year in order
(`Calendrical.Week.weeks_of_month/3`).

### Arguments

* `year` and `month` are a month of this calendar.

### Returns

* A list of `t:Date.Range.t/0`, one for each week `week_of_month/3`
  names for the month, the first of which may begin in the month
  before and the last run into the month after, or

* `{:error, exception}` for a month the year does not have.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.weeks_of_month(date.year, date.month) |> Enum.all?(&(Enum.count(&1) == 7))
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidMonthError{}} = Calendrical.Islamic.UmmAlQura.weeks_of_month(date.year, 99)

# `written_date`

Returns the figures a date is written with: its own fields, in a
calendar whose dates are written as its own.

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{year, month, day}` as the date is written, where the month of a
  lunisolar calendar is its traditional number, `{month, :leap}`
  for a leap month.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year, month, day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> Calendrical.Islamic.UmmAlQura.date_from_written_date(year, month, day) == {:ok, {date.year, date.month, date.day}}
    true

# `written_month_from_cldr_month`

Returns the month a CLDR month is written with in a year
(`Calendrical.Month.written_month_from_cldr_month/3`).

### Arguments

* `year` is a year of this calendar.

* `cldr_month` is a CLDR month number, or `{month, :leap}`.

### Returns

* The month as `written_date/3` writes it, or

* `{:error, :invalid_month}` where the year has no month of that
  name. The reason is an atom, not an exception: Localize's date parser
  reads it, where `Calendrical.Month.written_month_from_cldr_month/3`
  answers with an exception.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {_year, written_month, _day} = Calendrical.Islamic.UmmAlQura.written_date(date.year, date.month, date.day)
    iex> cldr_month = Calendrical.Islamic.UmmAlQura.cldr_month(date.year, date.month)
    iex> Calendrical.Islamic.UmmAlQura.written_month_from_cldr_month(date.year, cldr_month) == written_month
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.written_month_from_cldr_month(date.year, 99)
    {:error, :invalid_month}

# `year`

Returns the days of a year (`Calendrical.Period.year/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* A `t:Date.Range.t/0`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a year the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for
  no year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> date in Calendrical.Islamic.UmmAlQura.year(date.year)
    true

    iex> {:error, %Calendrical.MissingFieldsError{}} = Calendrical.Islamic.UmmAlQura.year(nil)

# `year_of_era`

Returns the year of era and era of a year (`Calendrical.Era.year_of_era/2`).

### Arguments

* `year` is a year of this calendar.

### Returns

* `{year_of_era, era}`, the era in effect on the year's first day,
  or

* `{:error, %Calendrical.InvalidDateError{}}` for a year the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for no
  year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> Calendrical.Islamic.UmmAlQura.year_of_era(date.year) ==
    ...>   Calendrical.Islamic.UmmAlQura.year_of_era(date.year, date.month, date.day)
    true

# `year_of_era`

Returns the year of era and era of a date (`Calendrical.Era.year_of_era/4`).

### Arguments

* `year`, `month` and `day` are a date of this calendar.

### Returns

* `{year_of_era, era}`, or

* `{:error, %Calendrical.InvalidDateError{}}` for a date the calendar does not have,
  or

* `{:error, exception}`, a `Calendrical.MissingFieldsError`, for no
  year.

### Examples

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {year_of_era, era} = Calendrical.Islamic.UmmAlQura.year_of_era(date.year, date.month, date.day)
    iex> year_of_era >= 1 and is_integer(era)
    true

    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Islamic.UmmAlQura.year_of_era(date.year, 99, 1)

# `years_in_cycle`

Returns the number of years after which this calendar's years
repeat, as its `info/0` states, or `{:error, %Calendrical.NotDefinedError{}}`.

### Returns

* The number of years in the cycle, or

* `{:error, %Calendrical.NotDefinedError{}}` where the calendar states none.

### Examples

    # A year has as many days as the year one cycle later
    iex> {:ok, date} = Date.convert(~D[2024-06-01], Calendrical.Islamic.UmmAlQura)
    iex> case Calendrical.Islamic.UmmAlQura.years_in_cycle() do
    ...>   {:error, %Calendrical.NotDefinedError{}} -> true
    ...>   years -> Calendrical.Islamic.UmmAlQura.days_in_year(date.year) == Calendrical.Islamic.UmmAlQura.days_in_year(date.year + years)
    ...> end
    true

---

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