# `Calendrical.Islamic.Observational`

Implementation of the *observational* (sighting-based) Islamic
calendar.

Unlike the tabular calendars in `Calendrical.Islamic.Civil` and
`Calendrical.Islamic.Tbla`, the start of each lunar month in this
calendar is determined by **actual visibility of the new crescent
moon** at a sample location. The location used here is **Cairo,
Egypt** (30.1° N, 31.3° E, 200 m), the canonical "Islamic location"
used by Dershowitz & Reingold's *Calendrical Calculations*.

This is the calendar identified by the CLDR `:islamic` calendar
type. Days are assumed to begin at midnight.

## Visibility model

Crescent visibility is computed by `Astro.new_visible_crescent/3`
using the **Odeh (2006)** criterion by default — a modern
empirical model fitted against 737 historical sightings. The Odeh
criterion replaces Reingold's older Shaukat criterion and is the
basis for several national Islamic calendar committees.

Months are 29 or 30 days long depending on whether the crescent
was visible on the eve of the 30th day; years are 354 or 355 days
long.

## Performance

Each calendar conversion makes a small number of crescent
visibility calls (typically 1-3, plus one new-moon search). The
underlying astronomical computations are not cached, so users that
need to convert many dates may benefit from caching results
externally.

## Reference

- Dershowitz & Reingold, *Calendrical Calculations* (4th ed.),
  Chapter 14, "The Islamic and Saudi Arabian Calendars".
- Odeh, M. Sh. (2004), *New Criterion for Lunar Crescent
  Visibility*. Experimental Astronomy 18, 39–64.
- CLDR `:islamic` calendar type.

See also `Calendrical.Islamic.Rgsa` for the same algorithm applied
at Mecca, and `Calendrical.Islamic.UmmAlQura` for the official
Saudi tabular calendar.

# `day`

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

# `month`

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

# `year`

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

# `calendar_base`

Identifies whether this calendar is month
or week based.

# `calendar_year`

```elixir
@spec calendar_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  Calendar.year()
```

Returns the calendar year as displayed
on rendered calendars.

# `cldr_calendar_type`

Defines the CLDR calendar type for this calendar.

This type is used in support of `Calendrical.
localize/3`.

# `cyclic_year`

```elixir
@spec cyclic_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  Calendar.year()
```

Returns the cyclic year as displayed
on rendered calendars.

# `date_from_iso_days`

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

Returns an observational Islamic `{year, month, day}` for the
given ISO day number.

# `date_to_iso_days`

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

Returns the number of ISO days for the given observational
Islamic `year`, `month`, and `day`.

# `day_of_era`

```elixir
@spec day_of_era(Calendar.year(), Calendar.month(), Calendar.day()) ::
  {day :: Calendar.day(), era :: Calendar.era()}
```

Calculates the day and era from the given
`year`, `month`, and `day`.

By default we consider on two eras: before the epoch
and on-or-after the epoch.

# `day_of_year`

```elixir
@spec day_of_year(Calendar.year(), Calendar.month(), Calendar.day()) :: Calendar.day()
```

Calculates the day of the year from the given
`year`, `month`, and `day`.

# `days_in_month`

```elixir
@spec days_in_month(Calendar.month()) ::
  Calendar.month()
  | {:ambiguous, Range.t() | [pos_integer()]}
  | {:error, :undefined}
```

Returns how many days there are in the given month.

Must be implemented in derived calendars because
we cannot know what the calendar format is.

# `days_in_month`

```elixir
@spec days_in_month(Calendar.year(), Calendar.month()) :: Calendar.month()
@spec days_in_month(year(), month()) :: 29..30
```

Returns the number of days in the given Hijri `year` and `month`
(29 or 30, determined by actual crescent visibility).

# `days_in_week`

Returns the number days in a a week.

# `days_in_year`

Returns the number of days in the given Hijri `year` (354 or 355).

# `epoch`

# `epoch_day_of_week`

# `extended_year`

```elixir
@spec extended_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  Calendar.year()
```

Returns the extended year as displayed
on rendered calendars.

# `first_day_of_week`

# `iso_week_of_year`

```elixir
@spec iso_week_of_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  {:error, :not_defined}
```

Calculates the ISO week of the year from the
given `year`, `month`, and `day`.

By default this function always returns
`{:error, :not_defined}`.

# `last_day_of_week`

# `leap_year?`

```elixir
@spec leap_year?(year()) :: boolean()
```

Returns whether the given Hijri `year` is a 355-day year (the
observational analogue of a "leap year").

Year length varies between 354 and 355 days depending on actual
crescent sightings, so this must be computed by comparing the
starts of two successive years.

# `location`

```elixir
@spec location() :: Geo.PointZ.t()
```

Returns the geographic location used to determine crescent
visibility for this calendar.

# `month`

Returns a `t:Date.Range.t/0` representing
a given month of a year.

# `month_of_year`

```elixir
@spec month_of_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  Calendar.month() | {Calendar.month(), Calendrical.leap_month?()}
```

Returns the month of the year from the given
`year`, `month`, and `day`.

# `months_in_leap_year`

Returns the number of months in a leap year.

# `months_in_ordinary_year`

Returns the number of months in a normal year.

# `months_in_year`

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

# `naive_datetime_from_iso_days`

```elixir
@spec naive_datetime_from_iso_days(Calendar.iso_days()) ::
  {Calendar.year(), Calendar.month(), Calendar.day(), Calendar.hour(),
   Calendar.minute(), Calendar.second(), Calendar.microsecond()}
```

Converts the `t:Calendar.iso_days` format to the
datetime format specified by this calendar.

# `naive_datetime_to_iso_days`

```elixir
@spec naive_datetime_to_iso_days(
  Calendar.year(),
  Calendar.month(),
  Calendar.day(),
  Calendar.hour(),
  Calendar.minute(),
  Calendar.second(),
  Calendar.microsecond()
) :: Calendar.iso_days()
```

Returns the `t:Calendar.iso_days` format of
the specified date.

# `periods_in_year`

Returns the number of periods in a given
`year`. A period corresponds to a month
in month-based calendars and a week in
week-based calendars.

# `plus`

Adds an `increment` number of `date_part`s
to a `year-month-day`.

`date_part` can be `:months` only.

# `quarter`

Returns a `t:Date.Range.t/0` representing
a given quarter of a year.

# `quarter_of_year`

```elixir
@spec quarter_of_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  Calendrical.quarter()
```

Returns the quarter of the year from the given
`year`, `month`, and `day`.

# `related_gregorian_year`

```elixir
@spec related_gregorian_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  Calendar.year()
```

Returns the related gregorain year as displayed
on rendered calendars.

# `valid_date?`

Determines if the given `year`, `month`, and `day` form a valid
observational Islamic date.

# `week`

Returns a `t:Date.Range.t/0` representing
a given week of a year.

# `week_of_month`

```elixir
@spec week_of_month(Calendar.year(), Calendar.month(), Calendar.day()) ::
  {pos_integer(), pos_integer()} | {:error, :not_defined}
```

Calculates the week of the year from the given
`year`, `month`, and `day`.

By default this function always returns
`{:error, :not_defined}`.

# `week_of_year`

```elixir
@spec week_of_year(Calendar.year(), Calendar.month(), Calendar.day()) ::
  {:error, :not_defined}
```

Calculates the week of the year from the given
`year`, `month`, and `day`.

By default this function always returns
`{:error, :not_defined}`.

# `weeks_in_year`

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

# `year`

Returns a `t:Date.Range.t/0` representing
a given year.

# `year_of_era`

```elixir
@spec year_of_era(Calendar.year()) :: {year :: Calendar.year(), era :: Calendar.era()}
```

Calculates the year and era from the given `year`.

# `year_of_era`

```elixir
@spec year_of_era(Calendar.year(), Calendar.month(), Calendar.day()) ::
  {year :: Calendar.year(), era :: Calendar.era()}
```

Calculates the year and era from the given `date`.

---

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