# `Localize.Calendar`
[🔗](https://github.com/elixir-localize/localize/blob/v1.4.0/lib/localize/calendar.ex#L1)

Calendar localization functions for retrieving locale-specific
names for eras, months, days, quarters, and day periods.

Also provides territory-based week preferences (first day of week,
weekend days) and functions to produce localized date part strings
from `Date`, `DateTime`, and `NaiveDateTime` structs.

## Display names

The `display_name/3` function provides a unified API for
localized calendar-related names, modeled on the JavaScript
`Intl.DisplayNames` API:

| Type | Value | Example result |
|---|---|---|
| `:calendar` | `:gregorian` | `"Gregorian Calendar"` |
| `:era` | `1` | `"Anno Domini"` |
| `:month` | `1` | `"January"` |
| `:day_of_week` | `1` (ISO Monday) | `"Monday"` |
| `:quarter` | `1` | `"1st quarter"` |
| `:day_period` | `:am` | `"AM"` |
| `:date_time_field` | `:year` | `"year"` |

All types support `:locale` and `:style` options. The `:month`,
`:day_of_week`, `:quarter`, and `:day_period` types also support a
`:context` option (`:format` or `:stand_alone`).

`:style` is the display width — `:wide` (the default),
`:abbreviated`, `:narrow`, or `:short`. Widths vary by type:
only the day types carry `:short`, and a width the type does not
have returns an error naming the widths it does.

## Naming a date's parts

`localize/3` is the same lookup addressed by a date rather than
by an explicit value: `localize(~D[2019-06-01], :month)` and
`display_name(:month, 6)` both return `{:ok, "June"}`. It derives
the part's value from the date and delegates, so the two take the
same options and always agree. Use it when you have a date, and
`display_name/3` when you have the value itself.

## Data access

Lower-level data access functions (`eras/2`, `months/2`,
`days/2`, `quarters/2`, `day_periods/2`) return full data
maps for use in formatting pipelines.

# `context`

```elixir
@type context() :: :format | :stand_alone
```

# `format`

```elixir
@type format() :: :wide | :abbreviated | :narrow
```

# `part`

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

# `acceptable_calendars`

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

Returns the acceptable CLDR calendar types.

### Returns

* A list of atoms.

### Examples

    iex> Localize.Calendar.acceptable_calendars()
    [:gregorian, :buddhist, :chinese, :coptic, :dangi, :ethiopic, :ethiopic_amete_alem, :hebrew, :indian, :islamic, :islamic_civil, :islamic_rgsa, :islamic_tbla, :islamic_umalqura, :japanese, :persian, :roc]

# `calendar_provider`

```elixir
@spec calendar_provider() :: module() | nil
```

Returns the module registered to answer for an application's calendars.

### Returns

* The provider module, or `nil` where none is registered.

### Examples

    iex> is_nil(Localize.Calendar.calendar_provider()) or
    ...>   is_atom(Localize.Calendar.calendar_provider())
    true

# `cyclic_years`

```elixir
@spec cyclic_years(Localize.locale(), atom()) ::
  {:ok, map()} | {:error, Exception.t()}
```

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

Cyclic year names are used by some calendar systems (such as
Chinese and Dangi) that follow a 60-year cycle of named years.

### Arguments

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

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

### Returns

* `{:ok, cyclic_year_data}` where `cyclic_year_data` is a map
  of cyclic name sets.

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, cyclic} = Localize.Calendar.cyclic_years(:en, :chinese)
    iex> Map.keys(cyclic) |> Enum.sort()
    [:day_parts, :days, :months, :solar_terms, :years, :zodiacs]

    iex> {:ok, cyclic} = Localize.Calendar.cyclic_years(:en, :chinese)
    iex> get_in(cyclic, [:zodiacs, :format, :abbreviated, 1])
    "Rat"

# `day_periods`

```elixir
@spec day_periods(Localize.locale(), atom()) :: {:ok, map()} | {:error, Exception.t()}
```

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

Day periods include AM/PM indicators and may include
additional periods like noon, midnight, morning, afternoon,
evening, and night.

### Arguments

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

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

### Returns

* `{:ok, day_period_data}` where `day_period_data` is a map
  keyed by context, format, period, and variant.

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, periods} = Localize.Calendar.day_periods(:en)
    iex> get_in(periods, [:format, :abbreviated, :am, :default])
    "AM"

# `days`

```elixir
@spec days(Localize.locale(), atom()) :: {:ok, map()} | {:error, Exception.t()}
```

Returns the day names for a locale and calendar type.

### Arguments

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

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

### Returns

* `{:ok, day_data}` where `day_data` is a map keyed by context
  (`:format`, `:stand_alone`), then format, then ISO day number
  (1 = Monday through 7 = Sunday).

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, days} = Localize.Calendar.days(:en)
    iex> get_in(days, [:format, :wide, 6])
    "Saturday"

# `display_name`

```elixir
@spec display_name(atom(), term(), Keyword.t()) ::
  {:ok, String.t()} | {:error, Exception.t()}
```

Returns a localized display name for a calendar-related item.

This is a unified API for retrieving localized names for
calendar systems, date-time fields, eras, months, days, quarters,
and day periods — modeled on the JavaScript `Intl.DisplayNames`
API.

### Summary

| Type | Value | Example result |
|---|---|---|
| `:calendar` | `:gregorian` | `"Gregorian Calendar"` |
| `:era` | `1` | `"Anno Domini"` |
| `:month` | `1` | `"January"` |
| `:day_of_week` | `1` (ISO Monday) | `"Monday"` |
| `:quarter` | `1` | `"1st quarter"` |
| `:day_period` | `:am` | `"AM"` |
| `:date_time_field` | `:year` | `"year"` |

### Arguments

* `type` is the type of calendar item. One of:

  * `:calendar` — a calendar system name, in CLDR's form
    (`:gregorian`) or its BCP 47 form (`:gregory`).

  * `:era` — an era name by index (e.g., `1` for AD).

  * `:quarter` — a quarter name by number (1–4).

  * `:month` — a month name by number (1–12).

  * `:day_of_week` — a day-of-week name by ISO day number (1–7,
    Monday–Sunday).

  * `:day_period` — a day period name (e.g., `:am`, `:pm`,
    `:noon`, `:midnight`).

  * `:date_time_field` — a date-time field label (e.g.,
    `:year`, `:month`, `:day`, `:hour`, `:minute`, `:second`).

* `value` is the value to look up. The type depends on
  the `type` argument (see above).

* `options` is a keyword list of options.

### Options

* `:locale` is a locale identifier. The default is
  `Localize.get_locale()`.

* `:style` is the display width. One of `:wide` (default),
  `:abbreviated`, `:narrow`, or `:short`. Not all styles are
  available for all types.

* `:context` is `:format` (default) or `:stand_alone`.
  Applies to `:month`, `:day_of_week`, `:quarter`, and `:day_period`.

* `:day_period` — if set to `:variant`, uses variant day period
  names ("am"/"pm" instead of "AM"/"PM" in English). Applies to
  the `:day_period` type.

* `:calendar` is the calendar system atom. The default is
  `:gregorian`.

* `:prefer` applies to the `:calendar` type. It is `:standard` (the
  default) for the full name, "Gregorian Calendar", or `:menu` for the
  short name CLDR gives for a menu of calendars, "Gregorian".

### Returns

* `{:ok, name}` where `name` is the localized display name.

* `{:error, exception}` if the value is not found.

### Examples

    iex> Localize.Calendar.display_name(:calendar, :gregorian)
    {:ok, "Gregorian Calendar"}

    iex> Localize.Calendar.display_name(:calendar, :gregory, prefer: :menu)
    {:ok, "Gregorian"}

    iex> Localize.Calendar.display_name(:month, 1)
    {:ok, "January"}

    iex> Localize.Calendar.display_name(:month, 1, style: :abbreviated)
    {:ok, "Jan"}

    iex> Localize.Calendar.display_name(:day_of_week, 1)
    {:ok, "Monday"}

    iex> Localize.Calendar.display_name(:day_of_week, 1, style: :narrow)
    {:ok, "M"}

    iex> Localize.Calendar.display_name(:day_period, :am)
    {:ok, "AM"}

    iex> Localize.Calendar.display_name(:date_time_field, :year)
    {:ok, "year"}

    iex> Localize.Calendar.display_name(:era, 1)
    {:ok, "Anno Domini"}

    iex> Localize.Calendar.display_name(:quarter, 1, style: :abbreviated)
    {:ok, "Q1"}

# `display_name!`

```elixir
@spec display_name!(
  :calendar
  | :era
  | :quarter
  | :month
  | :day_of_week
  | :day_period
  | :date_time_field,
  term(),
  Keyword.t()
) :: String.t()
```

Same as `display_name/3` but raises on error.

### Arguments

* `type` is the type of calendar item (`:calendar`, `:era`,
  `:quarter`, `:month`, `:day_of_week`, `:day_period`, or
  `:date_time_field`). See `display_name/3`.

* `value` is the value to look up. The type depends on the
  `type` argument.

* `options` is a keyword list of options.

### Options

See `display_name/3` for the supported options.

### Returns

* The localized display name as a string.

* Raises an exception if the value is not found.

### Examples

    iex> Localize.Calendar.display_name!(:month, 1)
    "January"

    iex> Localize.Calendar.display_name!(:quarter, 1, style: :abbreviated)
    "Q1"

# `eras`

```elixir
@spec eras(Localize.locale(), atom()) :: {:ok, map()} | {:error, Exception.t()}
```

Returns the era names for a locale and calendar type.

### Arguments

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

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

### Returns

* `{:ok, era_data}` where `era_data` is a map keyed by format
  (`:abbreviated`, `:wide`, `:narrow`) and era index.

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, eras} = Localize.Calendar.eras(:en)
    iex> get_in(eras, [:abbreviated, 1])
    "AD"

# `first_day_for_locale`

```elixir
@spec first_day_for_locale(Localize.locale()) :: integer() | {:error, Exception.t()}
```

Returns the first day of the week for a locale.

The day is found as TR35's first day algorithm finds it: a `-u-fw-`
day, else the first day of a `-u-rg-` region, else Monday for the
`-u-ca-iso8601` calendar, else the first day of the locale's region,
of its `-u-sd-` subdivision's region, of the region its likely
subtags add, or of the world.

### Arguments

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

### Returns

* An integer from 1 to 7 (Monday is 1).

* `{:error, exception}` if the locale is invalid.

### Examples

    iex> Localize.Calendar.first_day_for_locale(:en)
    7

    iex> Localize.Calendar.first_day_for_locale("en-u-fw-mon")
    1

    iex> Localize.Calendar.first_day_for_locale("en-u-rg-gbzzzz")
    1

    iex> Localize.Calendar.first_day_for_locale("en-u-ca-iso8601")
    1

# `first_day_for_territory`

```elixir
@spec first_day_for_territory(atom()) :: integer() | {:error, Exception.t()}
```

Returns the first day of the week for a territory.

Day numbers follow ISO 8601: 1 = Monday through 7 = Sunday.

### Arguments

* `territory` is a territory atom (e.g., `:US`, `:GB`).

### Returns

* An integer from 1 to 7.

* `{:error, exception}` if `territory` is not an atom.

### Examples

    iex> Localize.Calendar.first_day_for_territory(:US)
    7

    iex> Localize.Calendar.first_day_for_territory(:GB)
    1

# `known_calendars`

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

Returns the list of known CLDR calendar types.

### Returns

* A list of calendar type atoms.

### Examples

    iex> calendars = Localize.Calendar.known_calendars()
    iex> :gregorian in calendars and :buddhist in calendars and :hebrew in calendars
    true

# `localize`

```elixir
@spec localize(map(), part(), Keyword.t()) ::
  {:ok, String.t() | [{1..7, String.t()}]} | {:error, Exception.t()}
```

Returns a localized string for a part of a date or time.

A month is named by its calendar: its `cldr_month/2` gives the CLDR
month whose name it takes, so
a year that begins in July names its first month July, and the Hebrew
and lunisolar calendars name each month whatever its place in the
year. A leap month takes CLDR's leap-year name for its month (the
Hebrew "Adar II"), or its month's name in the calendar's leap-month
pattern (the Chinese "Second Monthbis"). A date's calendar is
`Calendar.ISO` or one implementing the Calendrical behaviour, which
answers these questions; any other is refused.

A part is named from the fields of the value it is asked of: an era
from the year, a quarter from the year and the month, a month from the
month, a day of the week from the year, the month and the day, and a day
period from the hour. A value that lacks one of them has no such part,
and is an error naming the field, as a pattern that asks for the part is
in `Localize.Date.to_string/2`.

### Arguments

* `datetime` is any `t:Date.t/0`, `t:Time.t/0`, `t:DateTime.t/0`, or
  `t:NaiveDateTime.t/0`, or a map with the fields `part` is named from.

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

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

### Options

* `:locale` is a locale identifier. The default is
  `Localize.get_locale()`.

* `:style` is the display width. One of `:wide` (default),
  `:abbreviated`, `:narrow`, or `:short`. Not all widths exist
  for all parts — only the day parts carry `:short` — and a
  width the part does not have returns an error listing the
  widths it does.

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

* `:era` — if set to `:variant`, uses variant era names
  ("Common Era" instead of "Anno Domini" in English).

* `:day_period` — if set to `:variant`, uses variant day period
  names ("am"/"pm" instead of "AM"/"PM" in English). Each
  variant option is named for the part it applies to.

### Returns

* `{:ok, name}` where `name` is the localized string.

* `{:ok, days}` where `days` is a list of
  `{day_number, day_name}` tuples, when `part` is
  `:days_of_week`.

* `{:error, %Localize.UnknownCalendarError{}}` if the date's
  calendar cannot answer for its parts.

* `{:error, %Localize.DateTimeInvalidInputError{}}` if the value lacks
  a field the part is named from, or holds one that is not an integer.

* `{:error, exception}` if the part cannot be localized.

### Examples

    iex> Localize.Calendar.localize(~D[2019-06-01], :month)
    {:ok, "June"}

    iex> {:error, error} = Localize.Calendar.localize(%{year: 2019}, :month)
    iex> error.missing
    [:month]

    iex> Localize.Calendar.localize(~D[2019-06-01], :month, style: :abbreviated)
    {:ok, "Jun"}

    iex> Localize.Calendar.localize(~D[2019-06-01], :day_of_week)
    {:ok, "Saturday"}

    iex> Localize.Calendar.localize(~D[2019-01-01], :era)
    {:ok, "Anno Domini"}

    iex> Localize.Calendar.localize(~D[2019-01-01], :era, era: :variant)
    {:ok, "Common Era"}

    iex> Localize.Calendar.localize(~D[2019-01-01], :quarter)
    {:ok, "1st quarter"}

# `localize!`

```elixir
@spec localize!(map(), part(), Keyword.t()) :: String.t() | [{1..7, String.t()}]
```

Same as `localize/3` but raises on error.

### Arguments

* `datetime` is any `t:Date.t/0`, `t:DateTime.t/0`, or
  `t:NaiveDateTime.t/0`.

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

* `options` is a keyword list of options.

### Options

See `localize/3` for the supported options.

### Returns

* The localized name, or the list of `{day_number, day_name}`
  tuples when `part` is `:days_of_week`.

* Raises an exception if the part cannot be localized.

### Examples

    iex> Localize.Calendar.localize!(~D[2019-06-01], :month)
    "June"

    iex> Localize.Calendar.localize!(~D[2019-06-01], :month, style: :abbreviated)
    "Jun"

# `min_days_for_locale`

```elixir
@spec min_days_for_locale(Localize.locale()) :: integer() | {:error, Exception.t()}
```

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

The `-u-ca-iso8601` calendar's weeks hold four days, as ISO 8601's
do. Any other locale takes the minimum days of the region TR35's
first day algorithm finds for it: a `-u-rg-` region, else the
locale's region, its `-u-sd-` subdivision's region, the region its
likely subtags add, or the world.

### Arguments

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

### Returns

* An integer from 1 to 7.

* `{:error, exception}` if the locale is invalid.

### Examples

    iex> Localize.Calendar.min_days_for_locale(:en)
    1

    iex> Localize.Calendar.min_days_for_locale(:de)
    4

    iex> Localize.Calendar.min_days_for_locale("en-u-ca-iso8601")
    4

# `min_days_for_territory`

```elixir
@spec min_days_for_territory(atom()) :: integer() | {:error, Exception.t()}
```

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

### Arguments

* `territory` is a territory atom.

### Returns

* An integer from 1 to 7.

* `{:error, exception}` if `territory` is not an atom.

### Examples

    iex> Localize.Calendar.min_days_for_territory(:US)
    1

    iex> Localize.Calendar.min_days_for_territory(:GB)
    4

# `month_patterns`

```elixir
@spec month_patterns(Localize.locale(), atom()) ::
  {:ok, map()} | {:error, Exception.t()}
```

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

Month patterns are used by some calendar systems (such as
Chinese and Hebrew) that have leap months. The patterns define
how to format month names in leap and non-leap contexts.

### Arguments

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

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

### Returns

* `{:ok, month_pattern_data}` where `month_pattern_data` is a map
  of month patterns keyed by context and format width.

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, patterns} = Localize.Calendar.month_patterns(:en, :chinese)
    iex> get_in(patterns, [:format, :narrow, :leap])
    [0, "b"]

# `months`

```elixir
@spec months(Localize.locale(), atom()) :: {:ok, map()} | {:error, Exception.t()}
```

Returns the month names for a locale and calendar type.

### Arguments

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

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

### Returns

* `{:ok, month_data}` where `month_data` is a map keyed by
  context (`:format`, `:stand_alone`), then format, then month
  number.

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, months} = Localize.Calendar.months(:en)
    iex> get_in(months, [:format, :wide, 6])
    "June"

# `quarters`

```elixir
@spec quarters(Localize.locale(), atom()) :: {:ok, map()} | {:error, Exception.t()}
```

Returns the quarter names for a locale and calendar type.

### Arguments

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

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

### Returns

* `{:ok, quarter_data}` where `quarter_data` is a map keyed
  by context (`:format`, `:stand_alone`), then format, then quarter
  number.

* `{:error, exception}` if the locale or calendar is not found.

### Examples

    iex> {:ok, quarters} = Localize.Calendar.quarters(:en)
    iex> get_in(quarters, [:format, :abbreviated, 2])
    "Q2"

# `register_provider`

```elixir
@spec register_provider(module() | nil) :: :ok
```

Registers the module that answers for the calendars an application
supplies.

A CLDR calendar type names no calendar module of its own, and Localize
ships `Calendar.ISO` alone. A value in another calendar is asked for the
calendars of its own family, and a value in `Calendar.ISO` has no family
to ask, so the provider answers for it: a locale's `-u-ca-` then names a
calendar for any value. The library supplying the calendars registers
itself as its application starts.

### Arguments

* `module` is the module answering `calendar_from_cldr_calendar_type/1`,
  which takes a CLDR calendar type and returns `{:ok, calendar}`. `nil`
  registers no provider.

### Returns

* `:ok`.

### Examples

    iex> previous = Localize.Calendar.calendar_provider()
    iex> Localize.Calendar.register_provider(MyApp.Calendars)
    :ok
    iex> Localize.Calendar.calendar_provider()
    MyApp.Calendars
    iex> Localize.Calendar.register_provider(previous)
    :ok

# `strftime_options!`

```elixir
@spec strftime_options!(Keyword.t()) :: Keyword.t()
```

Returns a keyword list of options for use with
`Calendar.strftime/3`.

The returned keyword list contains callback functions that
produce localized month names, day names, and AM/PM indicators.

`Calendar.strftime/3` passes a month-name callback the month number
alone, so a month is named by that number. For a calendar whose month
names do not follow a month's position in its year (the Hebrew and
lunisolar calendars), name the month with `localize/3` instead.

### Arguments

* `options` is a keyword list.

### Options

* `:locale` is a locale identifier. The default is `:en`.

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

### Returns

* A keyword list with `:am_pm_names`, `:month_names`,
  `:abbreviated_month_names`, `:day_of_week_names`, and
  `:abbreviated_day_of_week_names` keys.

### Examples

    iex> options = Localize.Calendar.strftime_options!(locale: :en)
    iex> options[:month_names].(6)
    "June"

    iex> options = Localize.Calendar.strftime_options!(locale: :de)
    iex> options[:abbreviated_day_of_week_names].(1)
    "Mo."

# `weekdays`

```elixir
@spec weekdays(atom()) :: [1..7, ...] | {:error, Exception.t()}
```

Returns the weekday numbers for a territory as a list
of ISO day-of-week numbers.

### Arguments

* `territory` is a territory atom.

### Returns

* A list of integers from 1 to 7.

* `{:error, exception}` if `territory` is not an atom.

### Examples

    iex> Localize.Calendar.weekdays(:US)
    [1, 2, 3, 4, 5]

# `weekend`

```elixir
@spec weekend(atom()) :: [integer()] | {:error, Exception.t()}
```

Returns the weekend days for a territory as a list
of ISO day-of-week numbers.

### Arguments

* `territory` is a territory atom.

### Returns

* A list of integers from 1 to 7.

* `{:error, exception}` if `territory` is not an atom.

### Examples

    iex> Localize.Calendar.weekend(:US)
    [6, 7]

    iex> Localize.Calendar.weekend(:IL)
    [5, 6]

---

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