Calendrical. Reform
(Calendrical v1.1.0)
Copy Markdown
Per-territory Julian-to-Gregorian reform calendars.
Different territories adopted the Gregorian calendar on different dates, ranging from the Catholic states in October 1582 to Greece in 1924. A historical date is only unambiguous once the territory it belongs to is known.
This module embeds a table of reform dates keyed by ISO 3166 territory code
and provides a factory, calendar_for/1, that returns a
Calendrical.Composite calendar splicing the Julian calendar before the
reform and the proleptic Gregorian calendar on and after it (e.g.
Calendrical.Reform.GB), derived automatically from the reform date.
The factory accepts a territory code (:GB) or a Localize.LanguageTag.t/0,
from which the territory is derived. The complete table is available from
reforms/0, so callers can inspect exactly how each calendar is generated.
The reform dates are those shipped by the Unix ncal(1) utility (from
FreeBSD's usr.bin/ncal/ncal.c). They record a single Julian-to-Gregorian
cutover per territory and are, in several cases, a simplification. Treat the
table as a reasonable default and override it with a hand-written composite
when a territory needs finer detail.
Accuracy and regional variation
For far more detailed, source-referenced accounts of when each country and
region adopted the Gregorian calendar, see Giuseppe Giudice's
The adoption of the Gregorian calendar
(drawing on the Explanatory Supplement to the Astronomical Ephemeris,
Ginzel, Schram and Cappelli) and Claus Tøndering's
Calendar FAQ. The ncal
dates agree with both for the territories that had a single national cutover —
the United Kingdom, France, Italy, Spain, Denmark, Russia, Bulgaria and
roughly a dozen others.
Where the ncal date is only representative, note:
Politically fragmented territories adopted the calendar over more than a century, by state, canton or province.
Calendrical.Reform.DEuses the Protestant 1700 date, but the Catholic German states changed in 1583–1584;Calendrical.Reform.NLuses an early Catholic-south 1582 date, though most Dutch provinces changed in 1700–1701;Calendrical.Reform.CH(1655) matches no single major Swiss canton, which ranged from 1584 (Catholic) to 1701 (Protestant) and later.AT,BEandSIare similar (SI's 1919 is the Yugoslav-union date; Slovenia proper was Gregorian from 1583).Calendrical.Reform.JP(Japan) is a poor fit for this model. Both references give Japan's adoption as 1 January 1873, and Japan was never on the Julian calendar (it used a lunisolar calendar beforehand), so a Julian-to-Gregorian splice does not describe its history. Thencal1918 date is retained only for parity with the source table; seeCalendrical.Reform.Japanfor the correct lunisolar-to-Gregorian model.Calendrical.Reform.GR(Greece) usesncal's 1924 date, which is the Orthodox church (Revised Julian) reckoning; the Greek civil calendar changed a year earlier, 16 February 1923 to 1 March 1923.US,AUandCAuse the 1752 British-Empire date.
In particular, Calendrical.Reform.SE uses ncal's simplified single 1753
cutover for Sweden. Sweden's actual history is more complex — it ran a
transitional calendar from 1700 to 1712, including the only known
30 February — and is modelled faithfully by Calendrical.Reform.Sweden.
Examples
iex> Calendrical.Reform.calendar_for(:GB)
{:ok, Calendrical.Reform.GB}
iex> :SE in Calendrical.Reform.known_territories()
true
Summary
Functions
Returns a Julian-to-Gregorian reform calendar module for the given ISO 3166 territory code.
Returns the sorted list of ISO 3166 territory codes for which a reform calendar is available.
Returns the Julian-to-Gregorian reform dates for a territory.
Returns the full reform table, so callers can see exactly how the reform calendars are generated.
Functions
@spec calendar_for(atom() | String.t() | Localize.LanguageTag.t()) :: {:ok, module()} | {:error, :unknown_territory}
Returns a Julian-to-Gregorian reform calendar module for the given ISO 3166 territory code.
When a territory has a hand-written, historically-detailed calendar, that
curated module is returned in preference to the ncal-derived one. Sweden
returns Calendrical.Reform.Sweden (which models the 1700–1712 transitional
period and 30 February 1712) and Japan returns Calendrical.Reform.Japan
(a lunisolar-to-Gregorian calendar, since Japan was never on the Julian
calendar). Every other territory is generated from the reform table.
The generated calendar module is created on first use and cached as a normal
Elixir module (e.g. Calendrical.Reform.GB). The call is idempotent: later
calls for the same territory return the same module.
Arguments
territoryis an ISO 3166 alpha-2 territory code, as an atom (:GB) or a string ("GB"), or aLocalize.LanguageTag.t/0from which the territory is derived viaLocalize.Territory.territory_from_locale/1.
Returns
{:ok, calendar_module}wherecalendar_moduleis aCalendrical.Compositecalendar implementing both theCalendarandCalendricalbehaviours.{:error, :unknown_territory}if the territory has no reform date.
Examples
iex> Calendrical.Reform.calendar_for(:RU)
{:ok, Calendrical.Reform.RU}
iex> Calendrical.Reform.calendar_for(:SE)
{:ok, Calendrical.Reform.Sweden}
iex> Calendrical.Reform.calendar_for(:JP)
{:ok, Calendrical.Reform.Japan}
iex> Calendrical.Reform.calendar_for(:XX)
{:error, :unknown_territory}
@spec known_territories() :: [atom(), ...]
Returns the sorted list of ISO 3166 territory codes for which a reform calendar is available.
Returns
- A sorted list of atoms (territory codes).
Examples
iex> territories = Calendrical.Reform.known_territories()
iex> :GB in territories and :SE in territories
true
@spec reform_date(atom() | String.t() | Localize.LanguageTag.t()) :: {:ok, %{last_julian: Date.t(), first_gregorian: Date.t()}} | {:error, :unknown_territory}
Returns the Julian-to-Gregorian reform dates for a territory.
Arguments
territoryis an ISO 3166 alpha-2 territory code, as an atom (:GB) or a string ("GB"), or aLocalize.LanguageTag.t/0from which the territory is derived viaLocalize.Territory.territory_from_locale/1.
Returns
{:ok, %{last_julian: last, first_gregorian: first}}wherelastis the last Julian date in the territory andfirstis the first Gregorian date.{:error, :unknown_territory}if the territory has no reform date.
Examples
iex> Calendrical.Reform.reform_date(:GB)
{:ok,
%{
last_julian: ~D[1752-09-02 Calendrical.Julian],
first_gregorian: ~D[1752-09-14 Calendrical.Gregorian]
}}
iex> Calendrical.Reform.reform_date(:XX)
{:error, :unknown_territory}
@spec reforms() :: %{ required(atom()) => %{ country: String.t(), last_julian: Date.t(), first_gregorian: Date.t() } }
Returns the full reform table, so callers can see exactly how the reform calendars are generated.
Returns
- A map keyed by ISO 3166 territory code. Each value is a map with the
:countryname, the:last_juliandate (aCalendrical.Juliandate) and the:first_gregoriandate (aCalendrical.Gregoriandate) — the day following the last Julian day.
Examples
iex> Calendrical.Reform.reforms()[:GB].first_gregorian
~D[1752-09-14 Calendrical.Gregorian]
iex> Calendrical.Reform.reforms()[:SE].last_julian
~D[1753-02-17 Calendrical.Julian]