Calendrical. Era
(Calendrical v2.2.0)
Copy Markdown
Era arithmetic for CLDR calendars.
Era definitions come from the era data in CLDR as Localize publishes it, where every era boundary is a proleptic Gregorian date. CLDR 49 carries the Japanese eras from Meiji onwards only; Localize supplies the earlier ones from its curated set, converted from their lunisolar proclamation dates. On first access the boundaries for a calendar type are resolved to ISO day counts and cached in :persistent_term, so lookups are lock-free and copy-free with no compile-time code generation.
Two year-numbering styles cover all CLDR calendars:
Most calendars number their years from the epoch of their primary era, so the year of era is the calendar year itself (
{year, era}). Years at or before zero belong to a "before" era when CLDR defines one (BCE, before ROC, before Hijra) and count backwards: year 0 is year 1 of that era.The Japanese calendar numbers years in Gregorian years while eras begin mid-year, so the era is selected by the date and the year of era is counted from each era's first Gregorian year.
A before era's days count back from its last day, as Calendar.ISO counts the days before the common era. A date before a calendar's first era, which TR35 gives no era, belongs to the first era counted back from its start: the year before its first is year 0, as ICU numbers the Japanese years before Taika, and the day before its first is day 0.
A calendar of one era with no before era, such as the Buddhist, Persian and Indian calendars, numbers the years before its year 1 as 0, -1 and so on in that era, as ICU does, where Calendar.ISO counts them in a second era.
Summary
Functions
Returns the cyclic year of a date: its place in the cycle its calendar's
info/0 names, reckoned as the East Asian sexagenary cycle is from the
related Gregorian year, or its year in a calendar whose years run in no
cycle.
Returns the day of era and era number for a date.
Returns the day of era and era of a date of a calendar, as the
calendar answers them: by its own day_of_era/3 where it defines one,
and otherwise by the era calendar its info/0 names (the member's, in
a composite calendar).
Returns the resolved era data for a CLDR calendar type.
Returns the year of era and era number for a date, by a calendar's
year-zero rule: year_of_era/3 with the rule of a calendar that has a
year 0.
Returns the extended year of a date: its year, numbered without a gap at 0 in a calendar that has no year 0, so 1 BC is 0 and 2 BC -1.
Returns the related Gregorian year of a date: the Gregorian year its calendar year begins in, as TR35 defines it, the same for every date of the year.
Returns the year of era and era of a year of a calendar: of its first
day, by the era calendar its info/0 names and its year-zero rule.
Returns the year of era and era number for a date.
Returns the year of era and era of a date of a calendar, as the
calendar answers them: by its own year_of_era/3 where it defines
one, and otherwise by the era calendar its info/0 names (the
member's, in a composite calendar) and its year-zero rule. A date with
no month or day is taken on the first day of its year.
Types
Functions
@spec cyclic_year(calendar(), Calendar.year(), Calendar.month(), Calendar.day()) :: integer() | {:error, Exception.t()}
Returns the cyclic year of a date: its place in the cycle its calendar's
info/0 names, reckoned as the East Asian sexagenary cycle is from the
related Gregorian year, or its year in a calendar whose years run in no
cycle.
Arguments
calendaris a calendar module.year,monthanddayare a date of the calendar.
Returns
- An integer, or
{:error, %Calendrical.InvalidDateError{}}for a year the calendar does not have, or{:error, Calendrical.MissingFieldsError.t()}for no year.
Examples
iex> Calendrical.Era.cyclic_year(Calendrical.Chinese, 4662, 1, 1)
42
iex> Calendrical.Era.cyclic_year(Calendrical.Gregorian, 2026, 1, 1)
2026
@spec day_of_era(cldr_calendar_type(), integer()) :: {integer(), Calendar.era()}
Returns the day of era and era number for a date.
Arguments
cldr_calendar_typeis the CLDR calendar type of the calendar, such as:persianor:japanese.iso_daysis the date as a count of days since the proleptic ISO epoch.
Returns
- A two-tuple
{day_of_era, era}whereday_of_eracounts from the era's first day, or back from a before era's last day. A date before the first era counts back from its start, so itsday_of_erais 0 or less.
Examples
iex> iso_days = Date.to_gregorian_days(~D[2019-05-01])
iex> Calendrical.Era.day_of_era(:japanese, iso_days)
{1, 236}
iex> iso_days = Date.to_gregorian_days(~D[1911-12-31])
iex> Calendrical.Era.day_of_era(:roc, iso_days)
{1, 0}
@spec day_of_era(calendar(), Calendar.year(), Calendar.month(), Calendar.day()) :: {integer(), Calendar.era()} | {:error, Exception.t()}
Returns the day of era and era of a date of a calendar, as the
calendar answers them: by its own day_of_era/3 where it defines one,
and otherwise by the era calendar its info/0 names (the member's, in
a composite calendar).
Arguments
calendaris a calendar module.year,monthanddayare a date of the calendar.
Returns
{day_of_era, era}, or{:error, %Calendrical.InvalidDateError{}}for a date the calendar does not have, or{:error, Calendrical.MissingFieldsError.t()}for a missing field.
Examples
iex> Calendrical.Era.day_of_era(Calendrical.Gregorian, 1, 1, 1)
{1, 1}
iex> Calendrical.Era.day_of_era(Calendrical.Japanese, 2019, 5, 1)
{1, 236}
@spec era_data(cldr_calendar_type()) :: map()
Returns the resolved era data for a CLDR calendar type.
The data is computed on first access and cached in
:persistent_term.
Arguments
cldr_calendar_typeis the CLDR calendar type of the calendar, such as:persianor:japanese.
Returns
- A map with the era records (most recent era first), the year-numbering mode and the forward/before era numbers.
Raises Localize.UnknownCalendarError for a type CLDR does not define.
Examples
iex> era_data = Calendrical.Era.era_data(:japanese)
iex> era_data.year_mode
:gregorian_offset
@spec era_year(cldr_calendar_type(), integer(), Calendar.year(), boolean()) :: {Calendar.year(), Calendar.era()}
Returns the year of era and era number for a date, by a calendar's
year-zero rule: year_of_era/3 with the rule of a calendar that has a
year 0.
Arguments
cldr_calendar_typeis the CLDR calendar type of the calendar, such as:persianor:japanese.iso_daysis the date as a count of days since the proleptic ISO epoch.yearis the year of the date in the calendar's own numbering.year_zero?is whether the calendar has a year 0: where it has, year 0 is year 1 of the era before, and where it has none, year -1 is.
Returns
- A two-tuple
{year_of_era, era}.
Examples
iex> Calendrical.Era.era_year(:gregorian, 0, -1, true)
{2, 0}
iex> Calendrical.Era.era_year(:gregorian, 0, -1, false)
{1, 0}
@spec extended_year(calendar(), Calendar.year(), Calendar.month(), Calendar.day()) :: integer() | {:error, Exception.t()}
Returns the extended year of a date: its year, numbered without a gap at 0 in a calendar that has no year 0, so 1 BC is 0 and 2 BC -1.
Arguments
calendaris a calendar module.year,monthanddayare a date of the calendar.
Returns
An integer, or
{:error, %Calendrical.InvalidDateError{}}for a date the calendar does not have, or{:error, %Calendrical.MissingFieldsError{}}for no year.
Examples
iex> Calendrical.Era.extended_year(Calendrical.Gregorian, -1, 1, 1)
-1
iex> Calendrical.Era.extended_year(Calendrical.Julian, -1, 1, 1)
0
@spec year_of_era(calendar(), Calendar.year()) :: {Calendar.year(), Calendar.era()} | {:error, Exception.t()}
Returns the year of era and era of a year of a calendar: of its first
day, by the era calendar its info/0 names and its year-zero rule.
Arguments
calendaris a calendar module.yearis a year of the calendar.
Returns
{year_of_era, era}, or{:error, %Calendrical.InvalidDateError{}}for a year the calendar does not have, or{:error, Calendrical.MissingFieldsError.t()}for no year.
Examples
iex> Calendrical.Era.year_of_era(Calendrical.Gregorian, -1)
{2, 0}
iex> Calendrical.Era.year_of_era(Calendrical.Julian, -1)
{1, 0}
@spec year_of_era(cldr_calendar_type(), integer(), Calendar.year()) :: {Calendar.year(), Calendar.era()}
Returns the year of era and era number for a date.
Arguments
cldr_calendar_typeis the CLDR calendar type of the calendar, such as:persianor:japanese.iso_daysis the date as a count of days since the proleptic ISO epoch.yearis the year of the date in the calendar's own numbering.
Returns
- A two-tuple
{year_of_era, era}.
Examples
iex> iso_days = Date.to_gregorian_days(~D[2019-05-01])
iex> Calendrical.Era.year_of_era(:japanese, iso_days, 2019)
{1, 236}
iex> Calendrical.Era.year_of_era(:persian, 0, 1405)
{1405, 0}
# Taika, the first Japanese era, began in 645
iex> iso_days = Date.to_gregorian_days(~D[0600-01-01])
iex> Calendrical.Era.year_of_era(:japanese, iso_days, 600)
{-44, 0}
@spec year_of_era( calendar(), Calendar.year(), Calendar.month() | nil, Calendar.day() | nil ) :: {Calendar.year(), Calendar.era()} | {:error, Exception.t()}
Returns the year of era and era of a date of a calendar, as the
calendar answers them: by its own year_of_era/3 where it defines
one, and otherwise by the era calendar its info/0 names (the
member's, in a composite calendar) and its year-zero rule. A date with
no month or day is taken on the first day of its year.
Arguments
calendaris a calendar module.year,monthanddayare a date of the calendar.
Returns
{year_of_era, era}, or{:error, %Calendrical.InvalidDateError{}}for a date the calendar does not have, or{:error, Calendrical.MissingFieldsError.t()}for no year.
Examples
iex> Calendrical.Era.year_of_era(Calendrical.Japanese, 2025, 6, 1)
{7, 236}
iex> Calendrical.Era.year_of_era(Calendrical.Gregorian, 2025, nil, nil)
{2025, 1}