# `Calendrical.Vietnamese`

Implementation of the Vietnamese lunisolar calendar (âm lịch).

The Vietnamese calendar is the Chinese lunisolar calendar observed from
a different meridian: new moons and solar terms are computed for **105°
East (Hanoi)** rather than Beijing. One year is divided into 12 months
(13 in a leap year), each running new moon to new moon, so a month has
29 or 30 days and an ordinary year 353, 354 or 355 days.

Because the reference meridian differs from China's, the Vietnamese New
Year (Tết) occasionally falls on a different day — or even a different
month — from the Chinese New Year. This happens only when a new moon or
the winter solstice falls in the one-hour window between UTC+7 and
UTC+8: 1985 (Tết a *month* before Chinese New Year), 2007, 2030 and
2053 (a day before). In every other year the two coincide.

## Reference meridian and its history

* **From 1 January 1968** the calendar is computed for the **105° East
  (Hanoi) meridian, UTC+7**, following North Vietnam's decree of 8 August
  1967 that switched standard time from UTC+8 to UTC+7.

* **Before 1968** Vietnam followed the Chinese calendar, so this
  implementation uses the Chinese calendar's meridian for that era —
  Beijing's local apparent time before 1929 and China Standard Time
  (UTC+8) from 1929 — and every pre-1968 date is therefore identical to
  `Calendrical.Chinese`.

All the documented divergences from the Chinese calendar are after 1968
and so use UTC+7. This follows Reingold & Dershowitz's *Calendrical
Calculations* (4th ed.); Hồ Ngọc Đức's published rules instead use a flat
105° East meridian for every date.

## CLDR calendar type

CLDR has no `vietnamese` calendar type, so this calendar borrows the
`:chinese` type for localization (month names and the sexagenary
stem/branch year names), exactly as `Calendrical.LunarJapanese` does.
The distinction from `Calendrical.Chinese` is the observation meridian,
not the localized names. There is correspondingly no registered
`-u-ca-vietnamese` BCP 47 subtag; select this calendar by module (or by
territory) rather than by a locale-tag calendar key.

The default epoch is `~D[-2636-02-15]`, the same as the Chinese calendar
(both share the sexagenary cycle), so a Vietnamese year number equals
the Chinese year number for the same date. It can be changed by setting
the `:vietnamese_epoch` configuration key in `config.exs`:

    config :calendrical,
      vietnamese_epoch: ~D[-2636-02-15]

## Two month numbering conventions

The Vietnamese lunisolar calendar (like the Chinese, Korean and Japanese
ones) has **two distinct month numbering conventions**. Choosing the
wrong one silently produces dates that are off by one full lunar month
after the intercalary month in leap years. The conventions are:

* **Ordinal** — months counted monotonically 1..12 in ordinary years
  and 1..13 in leap years. The intercalary appears at whatever position
  the astronomical no-zhongqi rule places it; it is not separately
  labelled. This is the convention `Date.new/4` accepts, the `Date.t`
  struct stores, and `Date.convert/2` returns. It is what the standard
  `Calendar` behaviour callbacks expect.

* **Traditional** — months always numbered 1..12, with the intercalary
  expressed as `{month, :leap}` (read *tháng N nhuận* in Vietnamese —
  "intercalary Nth month") where `month` is the *preceding* traditional
  month number. This is the convention used by cultural references and
  primary sources. `Calendrical.Vietnamese.new/3` and the return value
  of `lunar_month_of_year/1` use this convention.

Converting between the two: if a year is a leap year, traditional
numbers below the leap-month position equal the ordinal numbers, and
traditional numbers at or above the leap-month position equal
ordinal-minus-one. `leap_month/1` returns the **ordinal** position of
the intercalary; `traditional_leap_month/1` returns the **traditional**
number that the intercalary repeats.

# `add`

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

### Arguments

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

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

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

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

### Returns

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

### Examples

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

# `calendar_base`

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

### Returns

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

* `:month` otherwise.

### Examples

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

# `calendar_from_cldr_calendar_type`

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

### Arguments

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

### Returns

* `{:ok, calendar_module}`, or

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

### Examples

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

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

# `cardinal_day`

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

### Arguments

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

### Returns

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

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

### Examples

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

# `cardinal_month`

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

### Arguments

* `month` is a month of this calendar.

### Returns

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

### Examples

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

# `cardinal_year`

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

### Arguments

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

### Returns

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

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

### Examples

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

# `cldr_calendar_type`

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

### Returns

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

### Examples

    iex> Calendrical.Vietnamese.cldr_calendar_type() == Calendrical.Vietnamese.info().cldr_calendar_type
    true

# `cldr_calendar_type`

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

### Arguments

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

### Returns

* A CLDR calendar type.

### Examples

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

# `cldr_month`

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

### Arguments

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

### Returns

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

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

### Examples

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

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

# `cycle_and_year`

```elixir
@spec cycle_and_year(Calendar.year()) :: {integer(), 1..60} | {:error, Exception.t()}
```

Returns the sexagenary cycle a year of this calendar is in, and the
year of the cycle it is.

### Arguments

* `year` is a year of this calendar.

### Returns

* `{cycle, cyclic_year}`, the cycle counted from 2637 BCE, the first
  year of the first cycle, and the year of it, 1 to 60, as
  `Calendrical.Era.cyclic_year/4` gives it, or

* `{:error, %Calendrical.InvalidDateError{}}` for a year that is not
  an integer.

### Examples

    iex> {:ok, date} = Date.convert(~D[2026-03-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.cycle_and_year(date.year)
    {78, 43}

# `cyclic_year`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `date_from_cardinal_date`

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

### Arguments

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

### Returns

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

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

### Examples

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

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

# `date_from_day_of_year`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

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

### Examples

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

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

# `date_from_week_date`

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

### Arguments

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

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

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

### Returns

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

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

### Examples

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

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

# `date_from_written_date`

Returns the date of this calendar that written figures name: the
inverse of `written_date/3`.

### Arguments

* `year` is a year of this calendar.

* `lunar_month` is a traditional month, or `{month, :leap}`.

* `day` is a day of the month.

### Returns

* `{:ok, {year, month, day}}` with the ordinal month.

* `{:error, :invalid_date}` for figures that name no date, an atom as
  `c:Calendrical.date_from_written_date/3` answers.

### Examples

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

# `dates_in_gregorian_year`

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

### Arguments

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

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

### Returns

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

### Examples

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

# `day_numbers`

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

### Arguments

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

### Returns

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

### Examples

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

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

# `day_of_era`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `day_of_week`

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

### Arguments

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

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

### Returns

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

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

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

### Examples

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

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

# `day_of_year`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `days_in_month`

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

### Arguments

* `month` is a month of this calendar.

### Returns

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

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

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

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

### Examples

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

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

# `days_in_month`

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

Returns the number of days in a month of a year, 29 or 30.

### Arguments

* `year` is a year of this calendar.

* `month` is an ordinal month of the year.

### Returns

* `29` or `30`, or

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

* `{:error, %Calendrical.UnsupportedDateRangeError{}}` for a year
  outside the supported years (see the module documentation), or

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

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.days_in_month(today.year, today.month) in [29, 30]
    true

# `days_in_month_bounds`

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

### Arguments

* `month` is a month of this calendar.

### Returns

* `{fewest, most}`, or

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

### Examples

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

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

# `days_in_week`

Returns the number of days in a week.

### Returns

* `7`.

### Examples

    iex> Calendrical.Vietnamese.days_in_week()
    7

# `days_in_year`

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

### Arguments

* `year` is a year of this calendar.

### Returns

* The number of days, or

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

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

### Examples

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

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

# `diff`

Returns the number of whole years, quarters, months, weeks or days
from one date to another, the months counted through the leap
months of the years between.

### Arguments

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

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

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

### Returns

* The number of whole units, negative when `to` is before `from`, or

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

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.diff({today.year, 1, 1}, {today.year + 1, 1, 1}, :years)
    1

# `elapsed_years`

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

Returns the year of this calendar that a sexagenary cycle and a year
of it name: the inverse of `cycle_and_year/1`.

### Arguments

* `cycle` is a sexagenary cycle, counted from 2637 BCE, the first
  year of the first cycle.

* `cyclic_year` is a year of the cycle, 1 to 60.

### Returns

* The year of this calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` for a cycle that is not
  an integer or a cyclic year that is not one of 1 to 60.

### Examples

    iex> year = Calendrical.Vietnamese.elapsed_years(78, 43)
    iex> {:ok, new_year} = Calendrical.Vietnamese.new(year, 1, 1)
    iex> Date.convert!(new_year, Calendar.ISO).year
    2026

    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Vietnamese.elapsed_years(78, 61)

# `epoch`

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

### Returns

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

### Examples

    iex> Calendrical.Vietnamese.epoch() |> is_integer()
    true

# `era_calendar_type`

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

### Returns

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

### Examples

    iex> Calendrical.Vietnamese.era_calendar_type() == Calendrical.Vietnamese.info().era_calendar_type
    true

# `extended_year`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `gregorian_date_for_lunar`

Returns the Gregorian date of a traditional lunar month and day in
the lunar year that begins in a Gregorian year.

### Arguments

* `gregorian_year` is a Gregorian year.

* `lunar_month` is a traditional month, 1 to 12, or `{month, :leap}`.

* `lunar_day` is a day of the month.

### Returns

* A `t:Date.t/0` in `Calendar.ISO`.

Raises `Calendrical.InvalidDateError` when the lunar year has no such
month, or the month no such day, and
`Calendrical.UnsupportedDateRangeError` for a Gregorian year outside
-20,000 to 20,000.

### Examples

    iex> %Date{calendar: Calendar.ISO, year: 2024} = Calendrical.Vietnamese.gregorian_date_for_lunar(2024, 1, 1)

    iex> Calendrical.Vietnamese.gregorian_date_for_lunar(2024, 1, 40)
    ** (Calendrical.InvalidDateError) [gregorian_year: 2024, lunar_month: 1, lunar_day: 40] is not a date

# `info`

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

### Returns

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

### Examples

    iex> Calendrical.Vietnamese.info().calendar
    Calendrical.Vietnamese

# `iso_week_of_year`

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

### Arguments

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

### Returns

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

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

### Examples

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

# `leap_month`

Returns the position of the year's leap month, or `nil`.

### Arguments

* `year` is a year of this calendar.

### Returns

* The ordinal month that is the leap month, counting it among the
  year's months, or `nil` if the year has none, as for anything but
  an integer year.

Raises `Calendrical.UnsupportedDateRangeError` for a year outside the
supported years (see the module documentation).

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.leap_month(today.year) in [nil | Enum.to_list(2..13)]
    true

# `leap_month?`

Returns whether a month of a year is the leap month.

### Arguments

* `year` is a year of this calendar.

* `month` is an ordinal month of the year, counting the leap month.

### Returns

* `true` if the month is the year's leap month, otherwise `false`,
  as it is for anything but an integer year.

Raises `Calendrical.UnsupportedDateRangeError` for a year outside the
supported years (see the module documentation).

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.leap_month?(today.year, 0)
    false

# `leap_year?`

Returns whether a year has thirteen months.

### Arguments

* `year` is a year of this calendar.

### Returns

* `true` if the year has thirteen months, otherwise `false`.

Raises `Calendrical.UnsupportedDateRangeError` for a year outside the
supported years (see the module documentation).

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.leap_year?(today.year) == (Calendrical.Vietnamese.months_in_year(today.year) == 13)
    true

# `lunar_month_of_year`

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

### Arguments

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

### Returns

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

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

### Examples

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

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

# `mid_autumn_for_gregorian_year`

```elixir
@spec mid_autumn_for_gregorian_year(Calendar.year()) :: Date.t()
```

Returns the Gregorian date of Tết Trung Thu (the Mid-Autumn Festival,
the 15th day of the 8th lunar month) for a given Gregorian year.

### Arguments

* `gregorian_year` is any year in the Gregorian calendar.

### Returns

* The Gregorian date of the Mid-Autumn Festival for the given year.

### Examples

    iex> Calendrical.Vietnamese.mid_autumn_for_gregorian_year(2023)
    ~D[2023-09-29]

# `month`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `month_from_traditional`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

* The month's position in the year, or

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

### Examples

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

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

# `month_numbers`

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

### Arguments

* `year` is a year of this calendar.

### Returns

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

### Examples

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

# `month_of_year`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `months_in_leap_year`

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

### Returns

* A positive integer.

### Examples

    iex> Calendrical.Vietnamese.months_in_leap_year() >= Calendrical.Vietnamese.months_in_ordinary_year()
    true

# `months_in_ordinary_year`

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

### Returns

* A positive integer.

### Examples

    iex> Calendrical.Vietnamese.months_in_ordinary_year() <= Calendrical.Vietnamese.months_in_leap_year()
    true

# `months_in_year`

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

### Returns

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

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

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

### Examples

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

# `months_in_year`

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

### Arguments

* `year` is the year in this calendar.

### Returns

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

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

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

### Examples

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

# `months_in_year_bounds`

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

### Returns

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

### Examples

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

# `naive_datetime_from_iso_days`

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

### Arguments

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

### Returns

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

### Examples

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

# `naive_datetime_to_iso_days`

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

### Arguments

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

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

### Returns

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

### Examples

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

# `named_month`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

### Examples

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

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

# `new`

Returns a date of this calendar from a year, a traditional lunar
month and a day.

### Arguments

* `year` is a year of this calendar.

* `lunar_month` is a traditional month, 1 to 12, or `{month, :leap}`
  for the leap month that follows it.

* `day` is a day of the month.

### Returns

* `{:ok, date}` with the date in this calendar, or

* `{:error, %Calendrical.InvalidDateError{}}` for what is no date, or

* `{:error, %Calendrical.UnsupportedDateRangeError{}}` for a year
  outside the supported years.

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> {:ok, %Date{month: 1, day: 1}} = Calendrical.Vietnamese.new(today.year, 1, 1)
    iex> {:error, %Calendrical.InvalidDateError{}} = Calendrical.Vietnamese.new(today.year, 1, 31)

# `new!`

Returns a date of this calendar from a year, a traditional lunar
month and a day, raising for what is no date (see `new/3`).

### Arguments

* `year` is a year of this calendar.

* `lunar_month` is a traditional month, 1 to 12, or `{month, :leap}`
  for the leap month that follows it.

* `day` is a day of the month.

### Returns

* The `t:Date.t/0` in this calendar.

Raises `Calendrical.InvalidDateError` for what is no date, and
`Calendrical.UnsupportedDateRangeError` for a year outside the
supported years.

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> %Date{month: 1, day: 1} = Calendrical.Vietnamese.new!(today.year, 1, 1)

# `new_year_for_gregorian_year`

Returns the Gregorian date of the new year that begins the lunar
year of a Gregorian year.

### Arguments

* `gregorian_year` is a Gregorian year.

### Returns

* A `t:Date.t/0` in `Calendar.ISO`.

### Examples

    iex> Calendrical.Vietnamese.new_year_for_gregorian_year(2024) == Calendrical.Vietnamese.gregorian_date_for_lunar(2024, 1, 1)
    true

# `numeric_month`

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

### Arguments

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

### Returns

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

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

### Examples

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

# `ordinal_month_from_traditional`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

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

### Examples

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

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

# `parse_date`

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

### Arguments

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

### Returns

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

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

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

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

### Examples

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

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

# `parse_naive_datetime`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `parse_utc_datetime`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `parsing_calendar`

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

### Returns

* A calendar module.

### Examples

    iex> Calendrical.Vietnamese.parsing_calendar() == Calendrical.Vietnamese.info().parsing_calendar
    true

# `parsing_calendars`

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

### Returns

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

### Examples

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

# `periods_in_year`

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

### Arguments

* `year` is a year of this calendar.

### Returns

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

### Examples

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

# `quadrimester`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

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

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

### Examples

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

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

# `quarter`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

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

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

### Examples

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

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

# `quarter_of_year`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

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

# `related_gregorian_year`

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

### Arguments

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

### Returns

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

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

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

### Examples

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

# `semester`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

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

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

### Examples

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

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

# `shift`

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

### Arguments

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

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

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

* `options` is a keyword list of options.

### Options

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

### Returns

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

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

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

### Examples

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

# `shift_date`

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

### Arguments

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

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

### Returns

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

### Examples

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

# `shift_naive_datetime`

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

### Arguments

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

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

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

### Returns

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

### Examples

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

# `shift_time`

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

### Arguments

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

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

### Returns

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

### Examples

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

# `solar_term`

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

### Arguments

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

* `gregorian_year` is a Gregorian year.

### Returns

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

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

### Examples

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

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

# `tet_for_gregorian_year`

```elixir
@spec tet_for_gregorian_year(Calendar.year()) :: Date.t()
```

Returns the Gregorian date of Tết (Vietnamese Lunar New Year) for a
given Gregorian year.

Tết is the 1st day of the 1st lunar month. It usually coincides with the
Chinese New Year, but diverges when a new moon or the winter solstice
falls in the UTC+7/UTC+8 window — in 1985 (a month earlier), 2007, 2030
and 2053 (a day earlier).

### Arguments

* `gregorian_year` is any year in the Gregorian calendar.

### Returns

* a `t:Date.t/0` for the Gregorian date of Tết.

### Examples

    iex> Calendrical.Vietnamese.tet_for_gregorian_year(2023)
    ~D[2023-01-22]

    # 1985: a full month before the Chinese New Year (20 February 1985)
    iex> Calendrical.Vietnamese.tet_for_gregorian_year(1985)
    ~D[1985-01-21]

    # 2007: a day before the Chinese New Year (18 February 2007)
    iex> Calendrical.Vietnamese.tet_for_gregorian_year(2007)
    ~D[2007-02-17]

# `traditional_leap_month`

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

### Arguments

* `year` is a year of this calendar.

### Returns

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

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

### Examples

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

# `traditional_month`

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

### Arguments

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

### Returns

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

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

### Examples

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

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

# `traditional_months`

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

### Arguments

* `year` is a year of this calendar.

### Returns

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

### Examples

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

# `valid_date?`

Returns whether a year, month and day are a date of this calendar.

### Arguments

* `year` is a year of this calendar.

* `month` is an ordinal month of the year.

* `day` is a day of the month.

### Returns

* `true` if they are a date of this calendar, otherwise `false`, as
  for a year outside the supported years.

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> Calendrical.Vietnamese.valid_date?(today.year, today.month, today.day)
    true
    iex> Calendrical.Vietnamese.valid_date?(today.year, today.month, 31)
    false

# `week`

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

### Arguments

* `year` is a year of this calendar.

* `week` is a week of the year.

### Returns

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

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

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

### Examples

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

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

# `week_date_from_date`

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

### Arguments

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

### Returns

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

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

### Examples

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

# `week_of_month`

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

### Arguments

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

### Returns

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

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

### Examples

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

# `week_of_year`

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

### Arguments

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

### Returns

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

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

### Examples

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

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

# `weeks_in_week_year`

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

### Arguments

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

### Returns

* The number of weeks, or

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

### Examples

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

# `weeks_in_year`

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

### Arguments

* `year` is a year of this calendar.

### Returns

* The number of weeks, or

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

### Examples

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

# `weeks_of_month`

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

### Arguments

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

### Returns

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

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

### Examples

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

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

# `written_date`

Returns the figures a date is written with: its year, its
traditional month and its day.

### Arguments

* `year` is a year of this calendar.

* `month` is an ordinal month of the year.

* `day` is a day of the month.

### Returns

* `{year, traditional_month, day}`, the traditional month an integer
  or `{month, :leap}` for a leap month.

### Examples

    iex> {:ok, today} = Date.convert(~D[2024-06-01], Calendrical.Vietnamese)
    iex> {year, _month, day} = Calendrical.Vietnamese.written_date(today.year, today.month, today.day)
    iex> {year, day} == {today.year, today.day}
    true

# `written_month_from_cldr_month`

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

### Arguments

* `year` is a year of this calendar.

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

### Returns

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

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

### Examples

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

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

# `year`

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

### Arguments

* `year` is a year of this calendar.

### Returns

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

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

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

### Examples

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

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

# `year_of_era`

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

### Arguments

* `year` is a year of this calendar.

### Returns

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

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

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

### Examples

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

# `year_of_era`

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

### Arguments

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

### Returns

* `{year_of_era, era}`, or

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

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

### Examples

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

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

# `years_in_cycle`

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

### Returns

* The number of years in the cycle, or

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

### Examples

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

---

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