# `Calendrical`

Calendar functions for calendars compatible with
Elixir's `Calendar` behaviour.

`Calendrical` supports the creation of calendars
that are variations on the proleptic Calendrical.Gregorian
calendar. It also adds additional functions, defined
by the `Calendrical` behaviour, to support these
derived calendars.

The common purpose of these derived calendars is
to support the creation and use of financial year
calendars that are commonly used in business.

There are two general types of calendars supported:

* `month` calendars that mirror the monthly structure
  of the proleptic `Calendrical.Gregorian` calendar but which are
  deemed to start the year in a month other than January.

* `week` calendars that are defined to have a 52 week
  structure (53 weeks in a long year). These calendars
  can be configured to start or end on the first, last or
  nearest day to the beginning or end of a `Calendrical.Gregorian`
  month.  The main intent behind this structure is to
  have each year start and end on the same day of the
  week with a consistent 13-week quarterly structure than
  enables a more straight forware comparison with
  same-period-last-year financial performance.

# `any_date_time`

```elixir
@type any_date_time() :: date() | time() | naive_date_time() | date_time()
```

Super type of any date or time.

# `calendar`

```elixir
@type calendar() :: module() | nil
```

Specifies the type of a calendar.

A calendar is a module that implements
the `Calendar` and `Calendrical`
behaviours. Calendar functions will
default to `Calendrical.Gregorian`
in most cases.

# `calendar_type`

```elixir
@type calendar_type() :: :month | :week
```

Specifies the type of a calendar

# `date`

```elixir
@type date() :: %{
  optional(:year) =&gt; year(),
  optional(:month) =&gt; month(),
  optional(:day) =&gt; day(),
  optional(:calendar) =&gt; calendar(),
  optional(any()) =&gt; any()
}
```

All date fields are optional however many functions
will require the presence of one or more - and
often all - fields be present.

# `date_time`

```elixir
@type date_time() :: %{
  optional(:calendar) =&gt; calendar(),
  optional(:day) =&gt; day(),
  optional(:hour) =&gt; Calendar.hour(),
  optional(:microsecond) =&gt; Calendar.microsecond(),
  optional(:minute) =&gt; Calendar.minute(),
  optional(:month) =&gt; month(),
  optional(:second) =&gt; Calendar.second(),
  optional(:std_offset) =&gt; Calendar.std_offset(),
  optional(:time_zone) =&gt; Calendar.time_zone(),
  optional(:utc_offset) =&gt; Calendar.utc_offset(),
  optional(:year) =&gt; year(),
  optional(:zone_abbr) =&gt; Calendar.zone_abbr(),
  optional(any()) =&gt; any()
}
```

All date time fields are optional however many functions
will require the presence of one or more - and
often all - fields be present.

# `day`

```elixir
@type day() :: Calendar.day() | nil
```

Specifies the day of a date as either
a positive integer or nil.

# `day_of_week`

```elixir
@type day_of_week() :: 1..7
```

Specifies the days of the week as integers.

Days of the week are encoded as the integers `1` through
`7` with `1` representing Monday and 7 representing Sunday.

Note that a calendar can be configured to start
on any day of the week. `day_of_week` is only a
way of encoding the days as an integer.

# `day_of_week_to_binary`

```elixir
@type day_of_week_to_binary() :: {day_of_week(), String.t()}
```

A mapping of a day of the week ordinal to the
localized string of the name of that day.

# `era`

```elixir
@type era() :: non_neg_integer() | nil
```

Specifies the year of a date as either
a positive integer or nil.

# `interval_relation`

```elixir
@type interval_relation() ::
  :precedes
  | :preceded_by
  | :meets
  | :met_by
  | :overlaps
  | :overlapped_by
  | :finished_by
  | :finishes
  | :contains
  | :during
  | :starts
  | :started_by
  | :equals
```

The types of relationship between two Date.Range intervals

# `iso_day_number`

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

Represents the number of days since the
calendar epoch.

The Calendar epoch is `0000-01-01`
in the proleptic gregorian calendar.

# `leap_month?`

```elixir
@type leap_month?() :: boolean()
```

Boolean indicating is this is a leap month

# `month`

```elixir
@type month() :: Calendar.month() | nil
```

Specifies the month of a date as either
a positive integer or nil.

# `naive_date_time`

```elixir
@type naive_date_time() :: %{
  optional(:calendar) =&gt; calendar(),
  optional(:day) =&gt; day(),
  optional(:hour) =&gt; Calendar.hour(),
  optional(:microsecond) =&gt; Calendar.microsecond(),
  optional(:minute) =&gt; Calendar.minute(),
  optional(:month) =&gt; month(),
  optional(:second) =&gt; Calendar.second(),
  optional(:year) =&gt; year(),
  optional(any()) =&gt; any()
}
```

All naive date time fields are optional however many functions
will require the presence of one or more - and
often all - fields be present.

# `part`

```elixir
@type part() ::
  :day_periods
  | :am_pm
  | :days_of_week
  | :day_of_week
  | :month
  | :quarter
  | :era
```

The part of a date, time or datetime that can be
localized.

# `precision`

```elixir
@type precision() :: :years | :quarters | :months | :weeks | :days
```

The precision for date intervals

# `quarter`

```elixir
@type quarter() :: 1..4
```

Specifies the quarter of year for a calendar date.

# `time`

```elixir
@type time() :: %{
  optional(:calendar) =&gt; Calendar.calendar(),
  optional(:hour) =&gt; Calendar.hour(),
  optional(:microsecond) =&gt; Calendar.microsecond(),
  optional(:minute) =&gt; Calendar.minute(),
  optional(:second) =&gt; Calendar.second(),
  optional(any()) =&gt; any()
}
```

All time fields are optional however many functions
will require the presence of one or more - and
often all - fields be present.

# `week`

```elixir
@type week() :: pos_integer()
```

Specifies the week of year for a calendar date.

# `year`

```elixir
@type year() :: Calendar.year() | nil
```

Specifies the year of a date as either
a positive integer or nil.

# `calendar_base`

```elixir
@callback calendar_base() :: :week | :month
```

Returns the calendar basis.

Returns either `:week` or `:month`.

# `calendar_year`

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

Returns a the year in a calendar year.

# `cldr_calendar_type`

```elixir
@callback cldr_calendar_type() ::
  :gregorian
  | :persian
  | :coptic
  | :ethiopic
  | :ethiopic_amete_alem
  | :chinese
  | :japanese
  | :dangi
  | :islamic
  | :islamic_civil
  | :islamic_rgsa
  | :islamic_tbla
  | :islamic_umalqura
  | :hebrew
  | :buddhist
  | :roc
  | :indian
```

Returns the CLDR calendar type.

Only algorithmic calendars are considered
in this implementation.

# `cyclic_year`

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

Returns a the cyclic year in a calendar year.

# `days_in_month`

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

Returns the number of days in a month (withoout a year).

# `days_in_year`

```elixir
@callback days_in_year(year :: year()) :: Calendar.day()
```

Returns the number of days in a year.

# `extended_year`

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

Returns a the extended year in a calendar year.

# `iso_week_of_year`

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

Returns a tuple of `{year, week_in_year}` for a given `year`, `month` or `week`, and `day`
for a a calendar.

The `iso_week_of_year` is calculated based on the ISO calendar.

# `month`

```elixir
@callback month(year :: year(), month :: month()) ::
  Date.Range.t() | {:error, :not_defined}
```

Returns a date range representing the days in a
given month for a calendar year.

# `month_of_year`

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

Returns the `month` for a given `year`, `month` or `week`, and `day`
for a a calendar.

The `month_of_year` is calculated based upon the calendar configuration.

# `periods_in_year`

```elixir
@callback periods_in_year(year :: year()) :: week() | Calendar.month()
```

Returns the number of periods (which are
months in a month calendar and weeks in a
week calendar) in a year

# `plus`

```elixir
@callback plus(
  year :: year(),
  month :: month() | week(),
  day :: day(),
  months_or_quarters :: :months | :quarters,
  increment :: integer(),
  options :: Keyword.t()
) :: {Calendar.year(), Calendar.month(), Calendar.day()}
```

Increments a `t:Calendar.date/0` or `t:Date.Range.t/0` by a specified positive
or negative integer number of periods (year, quarter, month,
week or day).

Calendars need only implement this callback for `:months` and `:quarters`
since all other date periods can be derived.

# `quarter`

```elixir
@callback quarter(year :: year(), quarter :: quarter()) ::
  Date.Range.t() | {:error, :not_defined}
```

Returns a date range representing the days in a
given quarter for a calendar year.

# `related_gregorian_year`

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

Returns a the related year in a calendar year.

# `week`

```elixir
@callback week(year :: year(), week :: week()) :: Date.Range.t() | {:error, :not_defined}
```

Returns a date range representing the days in a
given week for a calendar year.

# `week_of_month`

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

Returns a tuple of `{month, week_in_month}` for a given `year`, `month` or `week`, and `day`
for a a calendar.

The `week_in_month` is calculated based upon the calendar configuration.

# `week_of_year`

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

Returns a tuple of `{year, week_in_year}` for a given `year`, `month` or `week`, and `day`
for a a calendar.

The `week_in_year` is calculated based upon the calendar configuration.

# `weeks_in_year`

```elixir
@callback weeks_in_year(year :: year()) ::
  {week(), Calendar.day()} | {:error, :not_defined}
```

Returns the number of weeks in a year.

# `year`

```elixir
@callback year(year :: year()) :: Date.Range.t() | {:error, :not_defined}
```

Returns a date range representing the days in a
calendar year.

# `calendar_for_territory`

Returns a calendar configured according to
the preferences defined for a territory.

# `calendar_from_cldr_calendar_type`

```elixir
@spec calendar_from_cldr_calendar_type(atom() | String.t()) ::
  {:ok, module()} | {:error, Exception.t()}
```

Returns the Calendrical calendar module associated
with a CLDR calendar type.

CLDR calendar types are the atoms (or their string
equivalents) returned by `Localize.validate_calendar/1`
and listed by `supported_cldr_calendar_types/0`. This
function maps such a type to the corresponding
Calendrical calendar module if it is loaded in the
current build.

### Arguments

* `calendar_type` is a CLDR calendar type as an atom
  or string. The string `"gregory"` is accepted as an
  alias for `:gregorian`.

### Returns

* `{:ok, calendar_module}` where `calendar_module`
  is the Calendrical calendar module for the given
  CLDR calendar type, or

* `{:error, exception}` where `exception` is an
  exception struct.

### Examples

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

    iex> Calendrical.calendar_from_cldr_calendar_type("gregory")
    {:ok, Calendrical.Gregorian}

    iex> Calendrical.calendar_from_cldr_calendar_type(:persian)
    {:ok, Calendrical.Persian}

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

    iex> Calendrical.calendar_from_cldr_calendar_type(:ethiopic_amete_alem)
    {:ok, Calendrical.Ethiopic.AmeteAlem}

    iex> Calendrical.calendar_from_cldr_calendar_type(:dangi)
    {:ok, Calendrical.Korean}

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

# `calendar_from_locale`

Return the calendar module for a locale.

### Arguments

* `locale` is any locale or locale name validated
  by `Localize.validate_locale/1`.  The default is
  `Localize.get_locale()` which returns the locale
  set for the current process.

### Returns

* `{:ok, calendar_module}` or

* `{:error, exception}` where `exception` is an exception struct

### Examples

    iex> Calendrical.calendar_from_locale("en-US")
    {:ok, Calendrical.US}

    iex> Calendrical.calendar_from_locale("en-GB-u-ca-gregory")
    {:ok, Calendrical.GB}

    iex> Calendrical.calendar_from_locale("fa-IR")
    {:ok, Calendrical.Persian}

    iex> Calendrical.calendar_from_locale("fa-IR-u-ca-gregory")
    {:ok, Calendrical.Persian}

# `calendar_from_territory`

Returns the calendar module preferred for
a territory.

### Arguments

* `territory` is any valid ISO3166-2 code as
  an `t:String.t/0` or upcased `atom`.

### Returns

* `{:ok, calendar_module}` or

* `{:error, exception}` where `exception` is an exception struct

### Examples

    iex> Calendrical.calendar_from_territory(:US)
    {:ok, Calendrical.US}

    iex> {:error, %Localize.UnknownTerritoryError{}} = Calendrical.calendar_from_territory(:YY)

### Notes

The overwhelming majority of territories have
`:gregorian` as their first preferred calendar
and therefore `Calendrical.Gregorian` or
a derivation of it will be returned for most
territories.

Returning any other calendar module would require:

1. That another calendar is preferred over `:gregorian`
   for a territory

2. That a calendar module is available to support
   that calendar.

As an example, Iran (territory `:IR`) prefers the
`:persian` calendar. If the optional library
[ex_cldr_calendars_persian](https://hex.pm/packages/ex_cldr_calendars_persian)
is installed, the calendar module `Calendrical.Persian` will
be returned. If it is not installed, `Calendrical.Gregorian`
will be returned as `:gregorian` is the second preference
for `:IR`.

# `calendar_module?`

Returns a boolean indicating if a module
is a `Calendrical` module.

# `calendar_year`

```elixir
@spec calendar_year(date()) :: Calendar.year() | {:error, Exception.t()}
```

Returns the `year` number for
a `date` that is the representation
used for a calendar.

The calendar year may be different the
the year in the struct. The struct year
is designed for convertability and for
date/time arithmetic.

The representation in rendered calendar
may be different. For example, in the Chinese
calendar the cardinal year since epoch is
stored in the struct but the calendar
year used for representation is the
sexigesimal year (a number between 1 and 60).

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* the calendar year as an
  integer.

### Examples

    iex> Calendrical.calendar_year(~D[2019-01-01])
    2019

    iex> Calendrical.calendar_year(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    2019

    iex> Calendrical.calendar_year(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    2019

# `convert`
*since 2.4.0* 

```elixir
@spec convert(Date.t() | Date.Range.t(), Calendar.calendar()) ::
  {:ok, Date.t() | Date.Range.t()} | {:error, :incompatible_calendars}
```

Converts a date or a date range to another calendar.

If the argument is a `t:Calendar.date/0`, `Date.convert/2` is used to
do the conversion.

If the argument is a `t:Date.Range.t/0` then `Date.convert/2` is
applied to the start and end of the range and a new range returned.

### Arguments

* `date_or_range` is any `t:Calendar.date/0` or ` t:Date.Range.t/0`.

* `calendar` is any valid calendar module.

### Returns

* `{:ok, converted_date_or_range}` or

* `{:error, :incompatible_calendars}`

### Example

# `current`

Returns the current date or date range for
a date period (year, quarter, month, week
or day).

### Arguments

* `date_or_date_range` is any `t:Calendar.date/0` or
  `t:Date.Range.t/0`.

* `period` is `:year`, `:quarter`, `:month`,
  `:week` or `:day`.

### Returns

When a `t:Calendar.date/0` is passed, a `t:Calendar.date/0` is
returned.  When a `t:Date.Range.t/0` is passed
a `t:Date.Range.t/0` is returned.

### Examples

    iex> Calendrical.current(~D[2019-01-01], :day)
    ~D[2019-01-01]

# `cyclic_year`

```elixir
@spec cyclic_year(date()) :: Calendar.year() | {:error, Exception.t()}
```

Returns the cycle `year`
number for a `date`.

A related gregorian year is the gregorian
year that is most closely associated with a
date that is in another calendar.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* the cyclic year as an integer.

### Examples

    iex> Calendrical.cyclic_year(~D[2019-01-01])
    2019

    iex> Calendrical.cyclic_year(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    2019

    iex> Calendrical.cyclic_year(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    2019

# `cyclic_years`

Returns the cyclic year data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of cyclic year data.

# `date_from_day_of_year`

Returns a `t:Calendar.date/0` from a year, day_of_year
and a calendar.

### Arguments

* `year` is any integer year that is valid in
  `calendar`.

* `day_of_year` is any valid ordinal day of
  `year`.

* `calendar` is any module implementing
  the `Calendar` and `Calendrical`
  behaviours. The default is `Calendrical.Gregorian`.

### Returns

* a `t:Calendar.date/0` or

* `{:error, :invalid_date}`

# `date_from_iso_days`

```elixir
@spec date_from_iso_days(Calendar.iso_days() | iso_day_number(), calendar()) ::
  Date.t() | {:error, :incompatible_calendars | :invalid_date}
```

Returns a date represented by a number of
days since the start of the epoch.

The start of the epoch is the date
`0000-01-01`.

## Argumenets

* `iso_days` is an integer representing the
  number of days since the start of the epoch.

* `calendar` is any module that implements
  the `Calendar` and `Calendrical` behaviours.

### Returns

* a `t:Calendar.date/0`

## Example

    iex> Calendrical.date_from_iso_days(737425, Calendar.ISO)
    ~D[2019-01-01]

    iex> Calendrical.date_from_iso_days(366, Calendar.ISO)
    ~D[0001-01-01]

    iex> Calendrical.date_from_iso_days(0, Calendar.ISO)
    ~D[0000-01-01]

# `date_from_list`

Returns a `t:Calendar.date/0` from a keyword list
and a calendar.

### Arguments

* `[year: year, month: month, day: day}` is a
  keyword list representing a date.

* `calendar` is any module implementing
  the `Calendar` and `Calendrical`
  behaviours. The default is `Calendrical.Gregorian`.

### Returns

* a `t:Calendar.date/0` or

* `{:error, :invalid_date}`

### Examples

    iex> Calendrical.date_from_list([year: 2019, month: 3, day: 25], Calendrical.Gregorian)
    %Date{calendar: Calendrical.Gregorian, day: 25, month: 3, year: 2019}

    iex> Calendrical.date_from_list([year: 2019, month: 2, day: 29], Calendrical.Gregorian)
    {:error, :invalid_date}

# `date_from_tuple`

Returns a `t:Calendar.date/0` from a date tuple of
`{year, month, day}` and a calendar.

### Arguments

* `{year, month, day}` is a tuple
  representing a date.

* `calendar` is any module implementing
  the `Calendar` and `Calendrical`
  behaviours. The default is `Calendrical.Gregorian`.

### Returns

* a `t:Calendar.date/0`.

### Examples

    iex> Calendrical.date_from_tuple({2019, 3, 25}, Calendrical.Gregorian)
    %Date{calendar: Calendrical.Gregorian, day: 25, month: 3, year: 2019}

    iex> Calendrical.date_from_tuple({2019, 2, 29}, Calendrical.Gregorian)
    {:error, :invalid_date}

# `date_to_iso_days`

```elixir
@spec date_to_iso_days(Date.t()) :: iso_day_number()
```

Returns the number of days since the start
of the epoch.

The start of the epoch is the date 0000-01-01.

## Argumenets

* `date` is any `t:Calendar.date/0`.

### Returns

* The integer number of days since the epoch
  for the given `date`.

## Example

    iex> Calendrical.date_to_iso_days(~D[2019-01-01])
    737425

    iex> Calendrical.date_to_iso_days(~D[0001-01-01])
    366

    iex> Calendrical.date_to_iso_days(~D[0000-01-01])
    0

# `date_to_string`

```elixir
@spec date_to_string(Date.t()) :: String.t()
```

Formats a date into a string representation.

Note that the output is not decorated with
the calendar module name.

## Example

    iex> Calendrical.date_to_string(~D[2019-12-04])
    "2019-12-04"

    iex> Calendrical.date_to_string(~D[2019-23-04 Calendrical.NRF])
    "2019-W23-4"

# `datetime_from_modified_julian_date`

Returns the DateTime (defaulting to UTC timezone)
for the given Modified Julian Day.

### Arguments

* `mjd` is a number representing days passed since November 17, 1858 (Julian Calendar)

### Returns

* a `t:DateTime.t/0` at UTC timezone.

### Examples

    iex> Calendrical.datetime_from_modified_julian_date(59848)
    ~U[2022-09-26 00:00:00.000Z]

    iex> Calendrical.datetime_from_modified_julian_date(59848.75)
    ~U[2022-09-26 18:00:00.000Z]

# `day_of_era`

```elixir
@spec day_of_era(date()) :: {Calendar.day(), Calendar.era()} | {:error, Exception.t()}
```

Returns the `{day_of_era, era}` for
a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a the days since the start of the era and
  the era of the year as a tuple.

### Examples

    iex> Calendrical.day_of_era ~D[2019-01-01]
    {737060, 1}

    iex> Calendrical.day_of_era(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    {737093, 1}

    iex> Calendrical.day_of_era(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    {737456, 1}

# `day_of_week`

# `day_of_week`

# `day_of_year`

```elixir
@spec day_of_year(date()) :: Calendar.day() | {:error, Exception.t()}
```

Returns the `day` of the year
for a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a the day of the year as an
  integer

### Examples

    iex> Calendrical.day_of_year(~D[2019-01-01])
    1

    iex> Calendrical.day_of_year(~D[2016-12-31])
    366

    iex> Calendrical.day_of_year(~D[2019-12-31])
    365

    iex> Calendrical.day_of_year(~D[2019-52-07 Calendrical.NRF])
    365

    iex> Calendrical.day_of_year(~D[2012-53-07 Calendrical.NRF])
    372

# `day_periods`

Returns the day period data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of day period data.

# `days`

Returns the day name data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of day name data.

# `days_in_month`

# `default_calendar`

Returns the default calendar.

# `do_cardinal_day_of_week`

# `eras`

Returns the era data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of era data.

# `extended_year`

```elixir
@spec extended_year(date()) :: Calendar.year() | {:error, Exception.t()}
```

Returns the extended `year` number for
a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* the extended calendar year as an
  integer.

### Examples

    iex> Calendrical.extended_year(~D[2019-01-01])
    2019

    iex> Calendrical.extended_year(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    2019

    iex> Calendrical.extended_year(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    2019

# `first_day_for_locale`

Returns the first day of a week for a given
locale where `1` means `Monday` and `7` means `Sunday`.

Note that the first day of the first week is commonly
not aligned with the first day of the year.

# `first_day_for_locale`

# `first_day_for_territory`

Returns the first day of the week for a
given territory.

### Arguments

* `territory` is any valid ISO3166-2 code.

### Returns

* The first day of the week for this territory.
  Here `1` means `Monday` and `7` means `Sunday`.

# `first_day_of_year`

```elixir
@spec first_day_of_year(date :: date()) :: Date.t() | {:error, :invalid_date}
```

Returns the first date of a `year`
for a `t:Calendar.date/0`.

### Arguments

* `date` is any `t:Calendar.date/0`.

### Returns

* a `t:Calendar.date/0`  or

* `{:error, :invalid_date}`

### Examples

    iex>  Calendrical.first_day_of_year(~D[2019-12-01])
    ~D[2019-01-01]

# `first_day_of_year`

```elixir
@spec first_day_of_year(year :: year(), calendar :: calendar()) ::
  Date.t() | {:error, :invalid_date}
```

Returns the first date of a `year`
in a `calendar`.

### Arguments

* `year` is any year.

* `calendar` is any module that implements
  the `Calendar` and `Calendrical`
  behaviours.

### Returns

* a `t:Calendar.date/0`  or

* `{:error, :invalid_date}`

### Examples

    iex> Calendrical.first_day_of_year(2019, Calendrical.Gregorian)
    %Date{calendar: Calendrical.Gregorian, day: 1, month: 1, year: 2019}

    iex> Calendrical.first_day_of_year(2019, Calendrical.NRF)
    %Date{calendar: Calendrical.NRF, day: 1, month: 1, year: 2019}

# `first_gregorian_day_of_year`

Returns the gregorian date of the first day of of a `year`
for a `calendar`.

### Arguments

* `year` is any integer year number.

* `calendar` is any module that implements the `Calendar` and
  `Calendrical` behaviours or `Calendar.ISO`

### Examples

    iex> Calendrical.first_gregorian_day_of_year(2019, Calendrical.Gregorian)
    %Date{calendar: Calendrical.Gregorian, day: 1, month: 1, year: 2019}

    iex> Calendrical.first_gregorian_day_of_year(2019, Calendrical.NRF)
    %Date{calendar: Calendrical.Gregorian, day: 3, month: 2, year: 2019}

    iex> Calendrical.first_gregorian_day_of_year(~D[2019-12-01])
    ~D[2019-01-01]

# `first_gregorian_day_of_year`

```elixir
@spec first_gregorian_day_of_year(year() | date(), calendar()) ::
  Date.t() | {:error, :invalid_date}
```

# `friday`

```elixir
@spec friday() :: 5
```

Returns the cardinal day number representing
Friday.

# `inspect`

```elixir
@spec inspect(term(), list()) :: Inspect.Algebra.t()
```

An `inspect_fun/2` that can be configured in
`Inspect.Opts` supporting inspection of user-defined
calendars.

This function can be configured in `IEx` for Elixir version 1.9
and later by:

    IEx.configure(inspect: [inspect_fun: &Calendrical.inspect/2])
    :ok

# `interval`

```elixir
@spec interval(
  date_from :: Date.t(),
  date_to_or_count :: Date.t() | non_neg_integer(),
  precision()
) ::
  [Date.t()]
```

Returns an `Enumerable` list of dates of a given precision
of either `:years`, `:quarters`, `:months`, `:weeks` or
`:days`.

### Arguments

* `date_from` is a any `t:Calendar.date/0` that is the start of the
  sequence.

* `date_to_or_count` is upper bound of the sequence
  as a `t:Calendar.date/0` or the number of dates in the
  sequence to be generated.

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

The sequence is generated starting with `date_from` until the next date
in the sequence would be after `date_to`.

### Notes

The sequence can be in ascending or descending date order
based upon whether `date_from` is greater than `date_to`.

### Returns

* A list of dates

### Examples

    iex> d = ~D[2019-01-31]
    ~D[2019-01-31]
    iex> d2 = ~D[2019-05-31]
    ~D[2019-05-31]
    iex> Calendrical.interval(d, 3, :months)
    [~D[2019-01-31], ~D[2019-02-28], ~D[2019-03-31]]
    iex> Calendrical.interval(d, d2, :months)
    [~D[2019-01-31], ~D[2019-02-28], ~D[2019-03-31],
     ~D[2019-04-30], ~D[2019-05-31]]

# `interval_stream`

```elixir
@spec interval_stream(
  date_from :: Date.t(),
  date_to_or_count :: Date.t() | non_neg_integer(),
  precision()
) :: fun()
```

Returns an a `Stream` function than can be lazily
enumerated.

This function has the same arguments and provides
the same functionality as `interval/3` except that
it is lazily evaluated.

### Arguments

* `date_from` is a any `t:Calendar.date/0` that is the start of the
  sequence.

* `date_to_or_count` is upper bound of the sequence
  as a `t:Calendar.date/0` or the number of dates in the
  sequence to be generated.

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

The sequence is generated starting with `date_from` until the next date
in the sequence would be after `date_to`.

### Notes

The sequence can be in ascending or descending date order
based upon whether `date_from` is greater than `date_to`.

### Returns

* A list of dates.

### Examples

    iex> d = ~D[2019-01-31]
    ~D[2019-01-31]
    iex> d2 = ~D[2019-05-31]
    ~D[2019-05-31]
    iex> Calendrical.interval_stream(d, 3, :months) |> Enum.to_list
    [~D[2019-01-31], ~D[2019-02-28], ~D[2019-03-31]]
    iex> Calendrical.interval_stream(d, d2, :months) |> Enum.to_list
    [~D[2019-01-31], ~D[2019-02-28], ~D[2019-03-31],
     ~D[2019-04-30], ~D[2019-05-31]]

# `iso_day_of_week`

```elixir
@spec iso_day_of_week(date()) :: Calendar.day_of_week()
```

Returns the ISO day of week for a `date`
where `1` means `Monday` and `7` means
`Sunday`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* An integer ISO day of week in the range
  `1..7` where `1` is `Monday` and `7` is
  `Sunday`.

### Examples

    iex> {:ok, us_calendar} = Calendrical.calendar_from_locale("en")
    iex> {:ok, us_date} = Date.new(2025, 1, 1, us_calendar)
    iex> Calendrical.iso_day_of_week(us_date)
    3

# `iso_days_to_day_of_week`

```elixir
@spec iso_days_to_day_of_week(Calendar.iso_days() | Calendar.day()) :: day_of_week()
```

Returns the day of the week for a given
`iso_day_number`

### Arguments

* `iso_day_number` is the number of days since the start
  of the epoch.  See `Calendrical.date_to_iso_days/1`.

### Returns

* An integer representing a day of the week where Monday
  is represented by `1` and Sunday is represented by `7`.

### Examples

    iex> days = Calendrical.date_to_iso_days(~D[2019-01-01])
    iex> Calendrical.iso_days_to_day_of_week(days) == Calendrical.tuesday()
    true

# `iso_week_of_year`

```elixir
@spec iso_week_of_year(date()) :: {Calendar.year(), week()} | {:error, Exception.t()}
```

Returns the `ISO week` number for
a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a the ISO week of the year as an
  integer or

* `{:error, :not_defined}` is the calendar
  does not support the concept of weeks.

### Examples

    iex> Calendrical.iso_week_of_year(~D[2019-01-01])
    {2019, 1}
    iex> Calendrical.iso_week_of_year(~D[2019-02-01])
    {2019, 5}
    iex> Calendrical.iso_week_of_year(~D[2019-52-01 Calendrical.NRF])
    {2020, 4}
    iex> Calendrical.iso_week_of_year(~D[2019-26-01 Calendrical.NRF])
    {2019, 30}
    iex> Calendrical.iso_week_of_year(~D[2019-12-01 Calendrical.Julian])
    {:error, :not_defined}

# `last_day_of_year`

```elixir
@spec last_day_of_year(date :: date()) :: Date.t()
```

Returns the last date of a `year`
for a `t:Calendar.date/0`.

### Arguments

* `date` is any `t:Calendar.date/0`.

### Returns

* a `t:Calendar.date/0`  or

* `{:error, :invalid_date}`

### Examples

    iex>  Calendrical.last_day_of_year(~D[2019-01-01])
    ~D[2019-12-31]

# `last_day_of_year`

```elixir
@spec last_day_of_year(year :: year(), calendar :: calendar()) :: Date.t()
```

Returns the last date of a `year`
for a `calendar`.

### Arguments

* `year` is any year.

* `calendar` is any module that implements
  the `Calendar` and `Calendrical`
  behaviours

### Returns

* a `t:Calendar.date/0`  or

* `{:error, :invalid_date}`

### Examples

    iex> Calendrical.last_day_of_year(2019, Calendrical.Gregorian)
    %Date{calendar: Calendrical.Gregorian, day: 31, month: 12, year: 2019}

    iex> Calendrical.last_day_of_year(2019, Calendrical.NRF)
    %Date{calendar: Calendrical.NRF, day: 7, month: 52, year: 2019}

# `last_gregorian_day_of_year`

Returns the gregorian date of the first day of a `year`
for a `calendar`.

### Arguments

* `year` is any integer year number or a `t:date/0`.

* `calendar` is any module that implements the `Calendar` and
  `Calendrical` behaviours or `Calendar.ISO`.

### Examples

    iex> Calendrical.last_gregorian_day_of_year(2019, Calendrical.Gregorian)
    %Date{calendar: Calendrical.Gregorian, day: 31, month: 12, year: 2019}

    iex> Calendrical.last_gregorian_day_of_year(2019, Calendrical.NRF)
    %Date{calendar: Calendrical.Gregorian, day: 1, month: 2, year: 2020}

    iex> Calendrical.last_gregorian_day_of_year(~D[2019-12-01])
    ~D[2019-12-31]

# `last_gregorian_day_of_year`

```elixir
@spec last_gregorian_day_of_year(date() | year(), calendar()) ::
  Date.t() | {:error, :invalid_date}
```

# `localize`
*since 1.19.0* 

```elixir
@spec localize(any_date_time()) ::
  {:ok, any_date_time()}
  | {:error, :incompatible_calendars}
  | {:error, Exception.t()}
```

Localize a date by converting it to calendar
introspected from the provided or default locale.

### Arguments

* `date` is any `t:Calendar.date/0`.

* `options` is a `t:Keyword.t/0` list of options. The default is
  `[]`.

### Options

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

### Returns

* `{:ok, date}` where `date` is converted into the calendar
  associated with the current or provided locale.

### Examples

    iex> Calendrical.localize(~D[2022-06-09], locale: "fr")
    {:ok, %Date{year: 2022, month: 6, day: 9, calendar: Calendrical.FR}}

# `localize`
*since 1.19.0* 

```elixir
@spec localize(any_date_time(), Keyword.t() | atom()) ::
  {:ok, any_date_time()}
  | {:error, :incompatible_calendars}
  | {:error, Exception.t()}
```

# `localize`

```elixir
@spec localize(any_date_time(), atom(), Keyword.t()) ::
  String.t() | {:error, :incompatible_calendars} | {:error, Exception.t()}
@spec localize(datetime :: any_date_time(), part :: part(), options :: Keyword.t()) ::
  String.t() | {:error, Exception.t()}
```

Returns a localized string for a part of
a `t:Calendar.date/0`.

### Arguments

* `date` is any `t:Calendar.date/0`.

* `part` is one of `:era`, `:quarter`, `:month`,
  `:day_of_week` or `:days_of_week`.

* `options` is a `t:Keyword.t/0` list of options.

### Options

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `:format` is one of `:wide`, `:abbreviated` or `:narrow`. The
  default is `:abbreviated`.

* `:era` will, if set to `:variant` localize the era using
  the variant data. In the `:en` locale, this will produce `CE` and
  `BCE` rather than the default `AD` and `BC`.

* `:am_pm` will, if set to `:variant` localize the "AM"/"PM"
  time period indicator with the variant data. In the `:en` locale,
  this will produce `am` and `pm` rather than the default `AM` and `PM`.

### Returns

* A string representing the localized date part, or

* A list of strings representing the days of the week for
  when `part` is `:days_of_week`. The days are in week order for
  the given date's calendar, or

* `{error, {exception_module, message}}` if an error is detected

### Examples

    iex> Calendrical.localize(~D[2019-01-01], :era)
    "AD"

    iex> Calendrical.localize(~D[2019-01-01], :era, era: :variant)
    "CE"

    iex> Calendrical.localize(~D[2019-01-01], :day_of_week)
    "Tue"

    iex> Calendrical.localize(~D[0001-01-01], :day_of_week)
    "Mon"

    iex> Calendrical.localize(~D[2019-01-01], :days_of_week)
    [{1, "Mon"}, {2, "Tue"}, {3, "Wed"}, {4, "Thu"}, {5, "Fri"}, {6, "Sat"}, {7, "Sun"}]

    iex> Calendrical.localize(~D[2019-06-01], :era)
    "AD"

    iex> Calendrical.localize(~D[2019-06-01], :quarter)
    "Q2"

    iex> Calendrical.localize(~D[2019-06-01], :month)
    "Jun"

    iex> Calendrical.localize(~D[2019-06-01], :day_of_week)
    "Sat"

    iex> Calendrical.localize(~D[2019-06-01], :day_of_week, format: :wide)
    "Saturday"

    iex> Calendrical.localize(~D[2019-06-01], :day_of_week, format: :narrow)
    "S"

    iex> Calendrical.localize(~D[2019-06-01], :day_of_week, locale: "ar")
    "السبت"

# `min_days_for_locale`

Returns the minimum days in the first week of a year
for a given locale.

# `min_days_for_locale`

# `min_days_for_territory`

# `modified_julian_day`

Returns the Modified Julian Day of
a `t:Calendar.date/0`.

### Arguments

* `date_or_datetime` is any `t:Calendar.date/0` or a `t:DateTime.t/0`.
  If a `t:DateTime.t/0` is given, the result will be given in
  the current timezone.

### Returns

* an number representing the
  Modified Julian Day of the `date`.

### Notes

The Modified Julian Day is the number of days
since November 17, 1858. Therefore this function
only returns valid values for dates after this
date.

### Examples

    iex> Calendrical.modified_julian_day(~D[2019-01-01])
    58484.0

    iex> Calendrical.modified_julian_day(~U[2019-01-01 12:00:00Z])
    58484.5

    iex> Calendrical.modified_julian_day(~U[2022-09-26 18:00:00.000Z])
    59848.75

    # If the given DateTime is not UTC, the result is given in
    # the local timezone. This example requires a time zone database
    # such as `tz` or `tzdata` to be configured.
    #
    #     dt = DateTime.shift_zone!(~U[2019-01-01 14:00:00Z], "America/Sao_Paulo")
    #     #=> #DateTime<2019-01-01 12:00:00-02:00 -02 America/Sao_Paulo>
    #     Calendrical.modified_julian_day(dt)
    #     #=> 58484.5

# `monday`

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

Returns the cardinal day number representing
Monday

# `month_names`
*since 2.3.0* 

```elixir
@spec month_names(calendar :: calendar(), options :: Keyword.t()) ::
  [{pos_integer(), String.t()}] | {:error, Exception.t()}
```

Returns a sorted list of tuples containing ordinal months and
month names for a give calendar.

### Arguments

* `calendar` is any calendar module.

* `options` is a keyword list of options.

### Options

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `:type` is one of `:stand_alone` or `:format`. The default
  is `:format`.

* `:format` is one of `:abbreviated`, `Lwide` or `:narrow`.
  The default is `:abbreviated`.

### Returns

* A sorted list of tuples of the format `{ordinal month number, month name}`.

### Examples

    iex> Calendrical.month_names(Calendar.ISO, format: :wide)
    %{
      1 => "January",
      2 => "February",
      3 => "March",
      4 => "April",
      5 => "May",
      6 => "June",
      7 => "July",
      8 => "August",
      9 => "September",
      10 => "October",
      11 => "November",
      12 => "December"
    }

    iex> Calendrical.month_names(Calendar.ISO, locale: :de)
    %{
      1 => "Jan.",
      2 => "Feb.",
      3 => "März",
      4 => "Apr.",
      5 => "Mai",
      6 => "Juni",
      7 => "Juli",
      8 => "Aug.",
      9 => "Sept.",
      10 => "Okt.",
      11 => "Nov.",
      12 => "Dez."
    }

    iex> Calendrical.month_names(Calendrical.Gregorian, locale: :fr, format: :narrow)
    %{
      1 => "J",
      2 => "F",
      3 => "M",
      4 => "A",
      5 => "M",
      6 => "J",
      7 => "J",
      8 => "A",
      9 => "S",
      10 => "O",
      11 => "N",
      12 => "D"
    }

# `month_of_year`

```elixir
@spec month_of_year(date()) ::
  Calendar.month()
  | {Calendar.month(), leap_month :: :leap}
  | {:error, Exception.t()}
```

Returns the `month` number for
a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* the month of the year as an
  integer

### Examples

    iex> Calendrical.month_of_year(~D[2019-01-01])
    1
    iex> Calendrical.month_of_year(~D[2019-12-01])
    12
    iex> Calendrical.month_of_year(~D[2019-52-01 Calendrical.NRF])
    12
    iex> Calendrical.month_of_year(~D[2019-26-01 Calendrical.NRF])
    6

# `month_patterns`

Returns the month pattern data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of month pattern data, or `nil` if no patterns exist.

# `months`

Returns the month name data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of month name data.

# `months_in_year`

# `new`

```elixir
@spec new(module(), calendar_type(), Keyword.t()) ::
  {:ok, calendar()} | {:module_already_exists, module()} | {:error, String.t()}
```

Creates a new proleptic gregrian calendar based upon the
provided configuration.

If a module exists with the `calendar_module` name then it
is returned, not recreated.

### Arguments

* `calendar_module` is an atom representing the module
  name of the created calendar.

* `calendar_type` is an atom of either `:month` or
  `:week` indicating which type of calendar is to
  be created.

* `config` is a Keyword list defining the configuration
  of the calendar.

### Returns

* `{:ok, module}` where `module` is the new calendar
  module that conforms to the `Calendar` and `Calendrical`
  behaviours or

* `{:module_already_exists, module}` if a module of the given
  calendar name already exists. It is not guaranteed
  that the module is in fact a calendar module in this case.

## Configuration options

The following options can be provided to create
a new calendar.

* `:weeks_in_month` defines the layout of
  weeks in a quarter for a week- or month-
  based calendar. The value must be one of
  `[4, 4, 5]`, `[4,5,4]` or `[5,4,4]`.
  The default is `[4,4,5]`. This option
  is ignored for `:month` based calendars
  that have the parameter `day_of_year: :first`.

* `:begins_or_ends` determines whether the calendar
  year begins or ends on the given `:day_of_week` and
  `:month_of_year`. The default is `:begins`.

* `:first_or_last` determines whether the calendar
  year starts (or ends) on the first, last or nearest
  `:day-of_week` and `:month_of_year`. The default
  is `:first`

* `:day_of_week` determines the day
  of the week on which this calendar begins
  or ends. It may be a number in the range
  `1..7` representing Monday to Sunday.
  It may also be `:first` indicating the
  the weeks are calculated from the first
  day of the calendar day irrespective of
  the day of the week. In this case the last
  week of the year may be less than 7 days
  in length. The default is `1`.

* `:month_of_year` determines the `Calendrical.Gregorian`
  month of year in which this calendar begins
  or ends. The default is `1`.

* `:year` is used to determine which calendar
  Gregogian year is applicable for a given
  calendar date. The valid options are `:first`,
  `:last` and `:majority`.  The default is
  `:majority`.

* `:min_days_in_first_week` is used to determine
  how many days of the `Calendrical.Gregorian` year must be in
  the first week of a calendar year. This is used
  when determining when the year starts for week-based
  years.  The default is `4` which is consistent with
  the [ISO Week calendar](https://en.wikipedia.org/wiki/ISO_week_date)

### Examples

Each calendar has a function `__config__/0` generated within
it and therefore the configuration of the included calendars
in `ex_cldr_calendars` provide insight into the behaviour
of the configuration parameters.

As an example here we define the [ISO Week calendar](https://en.wikipedia.org/wiki/ISO_week_date)
calendar in full:

```
defmodule ISOWeek do
  use Calendrical.Base.Week,
    day_of_week: 1,              # Weeks begin or end on Monday
    month_of_year: 1,            # Years begin or end in January
    min_days_in_first_week: 4,   # 4 Calendrical.Gregorian days of the year must be in the first week
    begins_or_ends: :begins,     # The year *begins* on the `day_of_week` and `month_of_year`
    first_or_last: :first,       # They year *begins* on the *first* `day_of_week` and `month_of_year`
    weeks_in_month: [4, 4, 5],   # The weeks are laid out as *months* in a `[4,4,5]` pattern
    year: :majority,             # Any given year is that in which the majority of Calendrical.Gregorian months fall
    locale: nil                  # No `locale` is used to aid configuration
end
```

This can be generated at runtime by:

    iex> {_, MyISOWeek} = Calendrical.new MyISOWeek, :week,
    ...>   day_of_week: 1,
    ...>   month_of_year: 1,
    ...>   min_days_in_first_week: 4,
    ...>   begins_or_ends: :begins,
    ...>   first_or_last: :first,
    ...>   weeks_in_month: [4, 4, 5],
    ...>   year: :majority

Note that `Calendrical.ISOWeek` is included as part of this
library.

# `next`

Returns the next date or date range for
a date period (year, quarter, month, week
or day).

### Arguments

* `date_or_date_range` is any `t:Calendar.date/0` or
  `t:Date.Range.t/0`.

* `period` is `:year`, `:quarter`, `:month`,
` :week` or `:day`.

### Returns

When a `t:Calendar.date/0` is passed, a `t:Calendar.date/0` is
returned.  When a `t:Date.Range.t/0` is passed
a `t:Date.Range.t/0` is returned.

### Examples

    iex> Calendrical.next(~D[2019-01-01], :day)
    ~D[2019-01-02]

    iex> Calendrical.next(~D[2019-01-01], :month)
    ~D[2019-02-01]

    iex> Calendrical.next(~D[2019-01-01], :quarter)
    ~D[2019-04-01]

    iex> Calendrical.next(~D[2019-01-01], :year)
    ~D[2020-01-01]

# `previous`

Returns the previous date or date range for
a date period (year, quarter, month, week
or day).

### Arguments

* `date_or_date_range` is any `t:Calendar.date/0` or
  `t:Date.Range.t/0`.

* `period` is `:year`, `:quarter`, `:month`,
  `:week` or `:day`.

* `options` is a `t:Keyword.t/0` list of options.

### Returns

When a `t:Calendar.date/0` is passed, a `t:Calendar.date/0` is
returned.  When a `t:Date.Range.t/0` is passed
a `t:Date.Range.t/0` is returned.

### Examples

    iex> Calendrical.previous(~D[2019-01-01], :day)
    ~D[2018-12-31]

    iex> Calendrical.previous(~D[2019-01-01], :quarter)
    ~D[2018-10-01]

    iex> Calendrical.previous(~D[2019-01-01], :month)
    ~D[2018-12-01]

    iex> Calendrical.previous(~D[2019-01-01], :year)
    ~D[2018-01-01]

# `quarter_of_year`

```elixir
@spec quarter_of_year(date()) :: quarter() | {:error, Exception.t()}
```

Returns the `quarter` number for
a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a the quarter of the year as an
  integer

### Examples

    iex> Calendrical.quarter_of_year(~D[2019-01-01])
    1

    iex> Calendrical.quarter_of_year(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    1

    iex> Calendrical.quarter_of_year(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    4

# `quarters`

Returns the quarter name data for a locale and calendar type.

### Arguments

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `calendar` is a calendar type atom. The default is `:gregorian`.

### Returns

* A map of quarter name data.

# `related_gregorian_year`

```elixir
@spec related_gregorian_year(date()) :: Calendar.year() | {:error, Exception.t()}
```

Returns the related gregorian `year`
number for a `date`.

A related gregorian year is the gregorian
year that is most closely associated with a
date that is in another calendar.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* the related gregorian year as an
  integer.

### Examples

    iex> Calendrical.related_gregorian_year ~D[2019-01-01]
    2019

    iex> Calendrical.related_gregorian_year(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    2019

    iex> Calendrical.related_gregorian_year(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    2019

# `saturday`

```elixir
@spec saturday() :: 6
```

Returns the cardinal day number representing
Saturday.

# `strftime`

Formats the given date, time, or datetime into a string.

This function is a thin wrapper around `Calendar.strftime/3` intended
to ease formatting for localized calendars. Localized strings will
be automatically injected as options to `Calendar.strftime/3`.

See `Calendar.strftime/3` for details of formatting strings and
other options.

Examples:

    iex> Calendrical.strftime(~D[2025-01-26 Calendrical.IL], "%a", locale: :he)
    "יום ב׳"

# `strftime_options!`

Returns a keyword list of options than can be applied to
`Calendar.strftime/3` or `Calendrical.strftime/3`.

`strftime_options!` returns a keyword list than can be used as
options to return localised names for days, months and am/pm.

## Arguments

* `options` is a set of keyword options. The default is `[]`.

## Options

* `:locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

* `:calendar` is the name of any known calendar. The default
  is `Calendrical.Gregorian`.

## Example

    iex: Calendrical.strftime_options!()
    [
      am_pm_names: #Function<0.32021692/1 in Calendrical.strftime_options/2>,
      month_names: #Function<1.32021692/1 in Calendrical.strftime_options/2>,
      abbreviated_month_names: #Function<2.32021692/1 in Calendrical.strftime_options/2>,
      day_of_week_names: #Function<3.32021692/1 in Calendrical.strftime_options/2>,
      abbreviated_day_of_week_names: #Function<4.32021692/1 in Calendrical.strftime_options/2>
    ]

## Typical usage

    iex> Calendar.strftime(~D[2025-01-26 Calendrical.IL], "%a",
    ...>   Calendrical.strftime_options!(calendar: Calendrical.IL, locale: "en"))
    "Mon"

# `sunday`

```elixir
@spec sunday() :: 7
```

Returns the cardinal day number representing
Sunday.

# `supported_cldr_calendar_types`

```elixir
@spec supported_cldr_calendar_types() :: [atom(), ...]
```

Returns the list of CLDR calendar types supported by
Calendrical.

The returned types are the names recognised by
`Localize.validate_calendar/1` and are the valid
inputs to `calendar_from_cldr_calendar_type/1`.

### Returns

* A list of CLDR calendar type atoms.

### Examples

    iex> calendars = Calendrical.supported_cldr_calendar_types()
    iex> :gregorian in calendars and :persian in calendars and :hebrew in calendars
    true

# `thursday`

```elixir
@spec thursday() :: 4
```

Returns the cardinal day number representing
Thursday.

# `tuesday`

```elixir
@spec tuesday() :: 2
```

Returns the cardinal day number representing
Tuesday.

# `validate_calendar`

Validates if the argument is a Calendrical
calendar module.

If the calendar is `Calendar.ISO` then the
validated calendar is returned as `Calendrical.Gregorian`.

### Arguments

* `calendar_module` is a module that implements the
  `Calendrical` behaviour.

### Returns

* `{:ok, calendar_module}` or

* `{:error, exception}` where `exception` is an exception struct

### Examples

    iex> Calendrical.validate_calendar(Calendrical.Gregorian)
    {:ok, Calendrical.Gregorian}

    iex> Calendrical.validate_calendar(Calendar.ISO)
    {:ok, Calendrical.Gregorian}

    iex> {:error, %Calendrical.InvalidCalendarModuleError{module: :not_a_calendar}} =
    ...>   Calendrical.validate_calendar(:not_a_calendar)

# `wednesday`

```elixir
@spec wednesday() :: 3
```

Returns the cardinal day number representing
Wednesday.

# `week_of_month`

```elixir
@spec week_of_month(date()) :: {Calendar.month(), week()} | {:error, Exception.t()}
```

Returns the `{month, week_number}`
for a `date`.

The nature of a week depends on the
calendar configuration and therefore
some results may be surprising.  For example
the date of December 31st 2018 is actually
in month one of the ISO Week calendar of
2019.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a tuple of the form `{month, week}` or

* `{:error, :not_defined}` if the calendar
  does not support the concept of weeks.

### Examples

    iex> Calendrical.week_of_month(~D[2019-01-01])
    {1, 1}
    iex> Calendrical.week_of_month(~D[2018-12-31])
    {1, 1}
    iex> Calendrical.week_of_month(~D[2019-01-01 Calendrical.BasicWeek])
    {1, 1}
    iex> Calendrical.week_of_month(~D[2018-12-31 Calendrical.BasicWeek])
    {12, 5}
    iex> Calendrical.week_of_month(~D[2018-12-31 Calendrical.Julian])
    {:error, :not_defined}

# `week_of_year`

```elixir
@spec week_of_year(date()) :: {Calendar.year(), week()} | {:error, Exception.t()}
```

Returns the `{year, week_number}`
for a `date`.

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a the week of the year as an
  integer or

* `{:error, :not_defined}` if the calendar
  does not support the concept of weeks.

### Examples

    iex> Calendrical.week_of_year(~D[2019-01-01])
    {2019, 1}
    iex> Calendrical.week_of_year(~D[2019-12-01])
    {2019, 48}
    iex> Calendrical.week_of_year(~D[2019-52-01 Calendrical.NRF])
    {2019, 52}
    iex> Calendrical.week_of_year(~D[2019-26-01 Calendrical.NRF])
    {2019, 26}
    iex> Calendrical.week_of_year(~D[2019-12-01 Calendrical.Julian])
    {:error, :not_defined}

# `weekday?`

```elixir
@spec weekday?(date(), Keyword.t()) :: boolean() | {:error, Exception.t()}
```

Returns whether a given date is a weekday.

Weekdays are locale-specific and depend on
the policies of a given territory (region, country).

### Arguments

* `date` is any `t:Calendar.date/0`.

* `options` is a `t:Keyword.t/0` list of options.

### Options

* `:locale` is any locale or locale name validated
  by `Localize.validate_locale/1`.  The default is
  `Localize.get_locale/0` which returns the locale
  set for the current process.

* `:territory` is any valid ISO-3166-2 territory
  that is validated by `Localize.validate_territory/1`.

### Notes

When identifying which territory context within which
to determine whether a given day is a weekday or not
the following order applies:

* A territory specified by the `:territory` option.

* The territory defined as part of the `:locale` option.

* The territory defined as part of the current processes
  default locale.

### Examples

    # The default locale is `en-001` for which
    # the territory is `001` (the world). The weekdays
    # for `001` are Monday to Friday
    iex> Calendrical.weekday?(~D[2019-03-23], locale: :en)
    false

    iex> Calendrical.weekday?(~D[2019-03-23], territory: "IS")
    false

    # Saturday is a weekday in India
    iex> Calendrical.weekday?(~D[2019-03-23], locale: :"en-IN")
    true

    # Friday is not a weekday in Saudi Arabia
    iex> Calendrical.weekday?(~D[2019-03-22], locale: :"ar-SA")
    false

    # Friday is not a weekday in Israel
    iex> Calendrical.weekday?(~D[2019-03-22], locale: :he)
    false

    iex> Calendrical.weekday?(~D[2019-03-22 Calendrical.IL], locale: :he)
    false

# `weekdays`

Returns a list of the days of the week that
are considered a weekend for a given
territory (country).

### Arguments

* `territory` is any valid ISO3166-2 code.

### Returns

* A list of integers representing the days of
  the week that are week days. Here `1` means
  `Monday` and `7` means `Sunday`.

### Notes

The list of days may not be monotonic. See
the example for Saudi Arabia below.

### Examples

    iex> Calendrical.weekdays("US")
    [1, 2, 3, 4, 5]

    iex> Calendrical.weekdays("IN")
    [1, 2, 3, 4, 5, 6]

    iex> Calendrical.weekdays("SA")
    [1, 2, 3, 4, 7]

    iex> {:error, %Localize.UnknownTerritoryError{}} = Calendrical.weekdays("yy")

# `weekend`

Returns a list of the days of the week that
are considered a weekend for a given
territory (region, country).

### Arguments

* `territory` is any valid ISO3166-2 code.

### Returns

* A list of integers representing the days of
  the week that are weekend days. Here `1` means
  `Monday` and `7` means `Sunday`.

### Examples

    iex> Calendrical.weekend("US")
    [6, 7]

    iex> Calendrical.weekend("IN")
    [7]

    iex> Calendrical.weekend("SA")
    [5, 6]

    iex> {:error, %Localize.UnknownTerritoryError{}} = Calendrical.weekend("yy")

# `weekend?`

```elixir
@spec weekend?(date(), Keyword.t()) :: boolean() | {:error, Exception.t()}
```

Returns whether a given date is a weekend day.

Weekend days are locale-specific and depend on
the policies of a given territory (country).

### Arguments

* `date` is any `t:Calendar.date/0`.

* `options` is a `t:Keyword.t/0` list of options.

### Options

* `:locale` is any locale or locale name validated
  by `Localize.validate_locale/1`.  The default is
  `Localize.get_locale/0` which returns the locale
  set for the current process.

* `:territory` is any valid ISO-3166-2 territory
  that is validated by `Localize.validate_territory/1`.

### Notes

When identifying which territory context within which
to determine whether a given day is a weekend or not
the following order applies:

* A territory specified by the `:territory` option.

* The territory defined as part of the `:locale` option.

* The territory defined as part of the current processes
  default locale.

### Examples

    # The default locale is `en-001` for which
    # the territory is `001` (the world). The weekend
    # for `001` is Saturday and Sunday
    iex> Calendrical.weekend? ~D[2019-03-23]
    true

    iex> Calendrical.weekend?(~D[2019-03-23], locale: :en)
    true

    iex> Calendrical.weekend?(~D[2019-03-23], territory: "IS")
    true

    # In India the official weekend is only Sunday
    iex> Calendrical.weekend?(~D[2019-03-23], locale: "en-IN")
    false

    # In Israel the weekend starts on Friday
    iex> Calendrical.weekend?(~D[2019-03-22], locale: :he)
    true

    iex> Calendrical.weekend?(~D[2019-03-22 Calendrical.IL], locale: :he)
    true

    # As it also does in Saudia Arabia
    iex> Calendrical.weekend?(~D[2019-03-22], locale: :"ar-SA")
    true

    # Sunday is not a weekend day in Saudi Arabia
    iex> Calendrical.weekend?(~D[2019-03-24], locale: :"ar-SA")
    false

# `weeks_in_year`

```elixir
@spec weeks_in_year(date()) ::
  {week(), Calendar.day_of_week()} | {:error, Exception.t()}
```

Returns the number of weeks in a year.

### Arguments

* `date` is any `t:Calendar.date/0` or an integer year
  or a map with one or more of the fields `:year`,
  `:month`, `:day` and optionally `:calendar`.

### Returns

* `{weeks_in_year, days_in_last_week}`

### Examples

    # For the default Calendar.ISO calendar the number of
    # weeks in a year is either 52 or 53 with each week
    # being 7 days. The first week may start in the Gregorian
    # year prior and end in the following Gregorian year.

    iex> Calendrical.weeks_in_year(~D[2022-01-01])
    {52, 7}

    iex> Calendrical.weeks_in_year(~D[2023-01-01])
    {53, 7}

    # For week calculations, the Calendrical.ISO and Calendrical.ISOWeek
    # have the same definition.

    iex> Calendrical.weeks_in_year(2023, Calendrical.ISO)
    {52, 7}

    iex> Calendrical.weeks_in_year(2020, Calendrical.ISOWeek)
    {53, 7}

    iex> Calendrical.weeks_in_year(~D[2026-W01-1 Calendrical.ISOWeek])
    {53, 7}

    # For calendars that are configured to have the first week
    # start on the first day of the year there will be a final
    # week 53 with either 1 or 2 days.

    iex> Calendrical.SequentialWeeks.weeks_in_year(2023)
    {53, 1}

    iex> Calendrical.SequentialWeeks.weeks_in_year(2020)
    {53, 2}

# `weeks_in_year`

```elixir
@spec weeks_in_year(year(), calendar()) ::
  {week(), Calendar.day_of_week()} | {:error, Exception.t()}
```

# `weeks_to_days`

```elixir
@spec weeks_to_days(integer()) :: integer()
```

Returns the number of days in `n` weeks

## Example

    iex> Calendrical.weeks_to_days(2)
    14

# `year_of_era`

```elixir
@spec year_of_era(date()) ::
  {Calendar.day(), Calendar.era()} | {:error, Exception.t()}
```

Returns the `{year_of_era, era}` for
a `date`.

*This function differs slightly
from `Date.year_of_era/1`. See the notes
below*

### Arguments

* `date` is any `t:Calendar.date/0` or a map with one or
  more of the fields `:year`, `:month`, `:day` and
  optionally `:calendar`.

### Returns

* a the year since the start of the era and
  the era of the year as a tuple.

### Notes

1. Unlike `Date.year_of_era/1`, this function supports
  eras that change part way through the calendar
  year. This is common in the Japanese calendar where
  the eras change when a new emperor is ordained which
  can happen at any time of year. Therefore this
  function is consistent with `Date.year_of_era/1` for
  the Gregorian and related calendars, but returns a
  different (and more accurate) result for the Japanese
  calendar.

2. This is also true for fiscal year calendars that
  start on a day other than January 1st. The year of
  era will depend on whether the calendar was configured
  with `year: :beginning`, `year: :ending` or `year: :majority`.

### Examples

    iex> Calendrical.year_of_era(~D[2019-01-01])
    {2019, 1}

    iex> Calendrical.year_of_era(Calendrical.first_day_of_year(2019, Calendrical.NRF))
    {2019, 1}

    iex> Calendrical.year_of_era(Calendrical.last_day_of_year(2019, Calendrical.NRF))
    {2019, 1}

---

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