Calendrical.Julian (Calendrical v0.9.0)

Copy Markdown

Implements the proleptic Julian calendar.

The Julian calendar is the calendar introduced by Julius Caesar in 46 BCE and used throughout Europe until the Gregorian reform of

  1. It is identical in structure to Calendrical.Gregorian — 12 months, 365 or 366 days, the same month lengths — but uses a simpler leap-year rule (every fourth year) and therefore drifts about three days every 400 years against the tropical year.

This module is implemented as a macro module: use Calendrical.Julian, new_year_starting_month_and_day: {1, 1} builds a Julian variant whose year begins on the given month-and-day. The pre-built variants Calendrical.Julian.Jan1, Calendrical.Julian.March1, Calendrical.Julian.March25, Calendrical.Julian.Sept1, and Calendrical.Julian.Dec25 correspond to historical "year-style" conventions used in different periods and regions.

The module itself is also a fully-functional calendar that can be used directly (~D[1500-03-15 Calendrical.Julian]), in which case the year begins on January 1.

Summary

Functions

Returns the CLDR calendar base for this calendar.

Returns the calendar year as displayed on rendered calendars.

Returns the CLDR calendar type for this calendar.

Returns the cyclic year as displayed on rendered calendars.

Returns a Julian {year, month, day} tuple for the given ISO day number.

Returns the number of ISO days for the given Julian year, month, and day.

Returns the day-of-era and era for the given Julian date.

Returns the day-of-week for the given Julian date.

Returns the day of the year (1-based) for the given Julian date.

Returns the number of days in the given month.

Returns the number of days in the given Julian year and month.

Returns the number of days in a Julian week.

Returns the number of days in the given Julian year.

Returns the extended year as displayed on rendered calendars.

Returns {:error, :not_defined} because ISO weeks are not defined for the Julian calendar.

Returns whether the given Julian year is a leap year.

Returns a Date.Range.t/0 representing a given Julian year-and-month.

Returns the month of the year for the given Julian date.

Returns the Julian naive-datetime tuple for the given Calendar.iso_days/0.

Returns the number of periods in the given Julian year.

Adds an increment of date_parts to a Julian year-month-day.

Returns a Date.Range.t/0 representing a given quarter of a Julian year.

Returns the quarter of the year for the given Julian date.

Returns the proleptic Gregorian year that contains the given Julian date.

Shifts a Julian date by the given Duration.t/0.

Returns whether the supplied year, month, and day is a valid Julian date.

Returns {:error, :not_defined} because the Julian calendar does not define a week-of-year scheme.

Returns {:error, :not_defined} because the Julian calendar does not define a week-of-month scheme.

Returns {:error, :not_defined} because the Julian calendar does not define a week-of-year scheme of its own.

Returns a Date.Range.t/0 representing the given Julian year.

Returns the year and era for the given Julian year.

Returns the year and era for the Julian date given by year, month, and day.

Types

day()

@type day() :: 1..31

month()

@type month() :: 1..12

year()

@type year() :: -9999..-1 | 1..9999

Functions

calendar_base()

Returns the CLDR calendar base for this calendar.

Returns

  • The atom :month (the Julian calendar is month-based).

Examples

iex> Calendrical.Julian.calendar_base()
:month

calendar_year(year, month, day)

@spec calendar_year(year(), month(), day()) :: Calendar.year()

Returns the calendar year as displayed on rendered calendars.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • The integer Julian year.

Examples

iex> Calendrical.Julian.calendar_year(2025, 1, 1)
2025

cldr_calendar_type()

Returns the CLDR calendar type for this calendar.

This type is used in support of Calendrical.localize/3.

Returns

  • The atom :gregorian (the Julian calendar uses the Gregorian CLDR variant for month, era and other localised names).

Examples

iex> Calendrical.Julian.cldr_calendar_type()
:gregorian

cyclic_year(year, month, day)

@spec cyclic_year(year(), month(), day()) :: Calendar.year()

Returns the cyclic year as displayed on rendered calendars.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • The integer Julian year (the Julian calendar has no cyclic component).

Examples

iex> Calendrical.Julian.cyclic_year(2025, 1, 1)
2025

date_from_iso_days(iso_days)

@spec date_from_iso_days(integer()) :: {year(), month(), day()}

Returns a Julian {year, month, day} tuple for the given ISO day number.

Arguments

  • iso_days is an integer count of days since the proleptic ISO epoch.

Returns

  • A three-tuple {year, month, day} in the Julian calendar.

Examples

iex> Calendrical.Julian.date_from_iso_days(740_000)
{2026, 1, 6}

date_to_iso_days(year, month, day)

@spec date_to_iso_days(year(), month(), day()) :: integer()

Returns the number of ISO days for the given Julian year, month, and day.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • An integer count of days since the proleptic ISO epoch.

Examples

iex> Calendrical.Julian.date_to_iso_days(2025, 1, 1)
739630

datetime_to_string(year, month, day, hour, minute, second, microsecond, time_zone, zone_abbr, utc_offset, std_offset, format)

See Calendar.ISO.datetime_to_string/12.

day_of_era(year, month, day)

@spec day_of_era(year(), month(), day()) :: {day :: pos_integer(), era :: 0..1}

Returns the day-of-era and era for the given Julian date.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • A two-tuple {day_in_era, era} where era is 0 or 1.

Examples

iex> Calendrical.Julian.day_of_era(2025, 1, 1)
{739994, 1}

day_of_week(year, month, day, atom)

@spec day_of_week(year(), month(), day(), 1..7 | :default) ::
  {Calendar.day_of_week(), first_day_of_week :: non_neg_integer(),
   last_day_of_week :: non_neg_integer()}

Returns the day-of-week for the given Julian date.

The day-of-week is an integer from 1 to 7, where 1 is Monday and 7 is Sunday.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

  • starting_on is :default for the calendar's natural week boundary (Monday).

Returns

  • A three-tuple {day_of_week, first_day_of_week, last_day_of_week}.

Examples

iex> Calendrical.Julian.day_of_week(2025, 1, 1, :default)
{2, 1, 7}

day_of_year(year, month, day)

@spec day_of_year(year(), month(), day()) :: 1..366

Returns the day of the year (1-based) for the given Julian date.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • An integer in the range 1..366.

Examples

iex> Calendrical.Julian.day_of_year(2025, 3, 1)
60

days_in_month(month)

@spec days_in_month(month()) :: Calendar.day() | {:error, :unresolved}

Returns the number of days in the given month.

Because February's length depends on whether the year is a leap year, this arity-1 form returns {:error, :unresolved} for month 2.

Arguments

  • month is a month in the range 1..12.

Returns

  • An integer day count, or {:error, :unresolved} for February.

Examples

iex> Calendrical.Julian.days_in_month(4)
30

iex> Calendrical.Julian.days_in_month(2)
{:error, :unresolved}

days_in_month(year, month)

@spec days_in_month(year(), month()) :: 28..31

Returns the number of days in the given Julian year and month.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

Returns

  • An integer in the range 28..31.

Examples

iex> Calendrical.Julian.days_in_month(2024, 2)
29

iex> Calendrical.Julian.days_in_month(2025, 2)
28

days_in_week()

Returns the number of days in a Julian week.

Returns

  • The integer 7.

Examples

iex> Calendrical.Julian.days_in_week()
7

days_in_year(year)

Returns the number of days in the given Julian year.

Arguments

  • year is any non-zero Julian year as an integer.

Returns

  • 365 for an ordinary year or 366 for a leap year.

Examples

iex> Calendrical.Julian.days_in_year(2024)
366

iex> Calendrical.Julian.days_in_year(2025)
365

extended_year(year, month, day)

@spec extended_year(year(), month(), day()) :: Calendar.year()

Returns the extended year as displayed on rendered calendars.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • The integer Julian year.

Examples

iex> Calendrical.Julian.extended_year(2025, 1, 1)
2025

iso_week_of_year(year, month, day)

@spec iso_week_of_year(year(), month(), day()) :: {:error, :not_defined}

Returns {:error, :not_defined} because ISO weeks are not defined for the Julian calendar.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • {:error, :not_defined}.

Examples

iex> Calendrical.Julian.iso_week_of_year(2025, 1, 1)
{:error, :not_defined}

leap_year?(year)

@spec leap_year?(year :: Calendar.year()) :: boolean()

Returns whether the given Julian year is a leap year.

Julian leap years occur every four years (every year divisible by 4 — unlike the Gregorian rule, the centurial exceptions do not apply).

Arguments

  • year is any non-zero Julian year as an integer.

Returns

  • true if the year contains 366 days; otherwise false.

Examples

iex> Calendrical.Julian.leap_year?(2024)
true

iex> Calendrical.Julian.leap_year?(2025)
false

iex> Calendrical.Julian.leap_year?(2100)
true

month(year, month)

Returns a Date.Range.t/0 representing a given Julian year-and-month.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

Returns

Examples

iex> Calendrical.Julian.month(2025, 2)
Date.range(~D[2025-02-01 Calendrical.Julian], ~D[2025-02-28 Calendrical.Julian])

month_of_year(year, month, day)

@spec month_of_year(year(), month(), day()) :: month()

Returns the month of the year for the given Julian date.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • The integer month.

Examples

iex> Calendrical.Julian.month_of_year(2025, 4, 1)
4

naive_datetime_from_iso_days(arg)

Returns the Julian naive-datetime tuple for the given Calendar.iso_days/0.

Arguments

Returns

  • A seven-tuple {year, month, day, hour, minute, second, microsecond}.

Examples

iex> Calendrical.Julian.naive_datetime_from_iso_days({739630, {43_200_000_000, 86_400_000_000}})
{2025, 1, 1, 12, 0, 0, {0, 6}}

naive_datetime_to_iso_days(year, month, day, hour, minute, second, microsecond)

Returns the Calendar.iso_days/0 form of the given Julian naive datetime.

Arguments

  • year, month, day, hour, minute, second, microsecond form the Julian naive datetime.

Returns

Examples

iex> Calendrical.Julian.naive_datetime_to_iso_days(2025, 1, 1, 12, 0, 0, {0, 0})
{739630, {43_200_000_000, 86_400_000_000}}

periods_in_year(year)

Returns the number of periods in the given Julian year.

A period corresponds to a month in month-based calendars and a week in week-based calendars.

Arguments

  • year is any non-zero Julian year as an integer.

Returns

  • The integer 12 (months per Julian year).

Examples

iex> Calendrical.Julian.periods_in_year(2025)
12

plus(year, month, day, date_part, increment, options \\ [])

Adds an increment of date_parts to a Julian year-month-day.

Arguments

  • year, month, day form the Julian date to shift.

  • date_part is one of :years, :quarters, :months, or :days.

  • increment is the integer number of date_parts to add (may be negative).

Options

  • :coerce (boolean, default false) — when true, clamps the resulting day-of-month to the last valid day of the new month if the original day overflows (so adding one month to 31 March yields 30 April rather than an invalid date).

Returns

  • A three-tuple {year, month, day} representing the shifted Julian date.

Examples

iex> Calendrical.Julian.plus(2025, 1, 1, :years, 1)
{2026, 1, 1}

iex> Calendrical.Julian.plus(2025, 1, 1, :months, 1)
{2025, 2, 1}

iex> Calendrical.Julian.plus(2025, 1, 1, :days, 1)
{2025, 1, 2}

quarter(year, quarter)

Returns a Date.Range.t/0 representing a given quarter of a Julian year.

Arguments

  • year is any non-zero Julian year as an integer.

  • quarter is an integer in the range 1..4.

Returns

Examples

iex> Calendrical.Julian.quarter(2025, 1)
Date.range(~D[2025-01-01 Calendrical.Julian], ~D[2025-03-31 Calendrical.Julian])

quarter_of_year(year, month, day)

@spec quarter_of_year(year(), month(), day()) :: 1..4

Returns the quarter of the year for the given Julian date.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • An integer in the range 1..4.

Examples

iex> Calendrical.Julian.quarter_of_year(2025, 4, 1)
2

shift_date(year, month, day, duration)

Shifts a Julian date by the given Duration.t/0.

Arguments

  • year, month, day form the Julian date to shift.

  • duration is a Duration.t/0.

Returns

  • A three-tuple {year, month, day} representing the shifted Julian date.

Examples

iex> Calendrical.Julian.shift_date(2025, 1, 1, Duration.new!(month: 1))
{2025, 2, 1}

shift_naive_datetime(year, month, day, hour, minute, second, microsecond, duration)

Shifts a naive datetime by the given Duration.t/0.

Arguments

  • year, month, day, hour, minute, second, microsecond form the Julian naive datetime to shift.

  • duration is a Duration.t/0.

Returns

  • A seven-tuple {year, month, day, hour, minute, second, microsecond} representing the shifted Julian naive datetime.

Examples

iex> Calendrical.Julian.shift_naive_datetime(2025, 1, 1, 12, 0, 0, {0, 0}, Duration.new!(day: 1))
{2025, 1, 2, 12, 0, 0, {0, 0}}

shift_time(hour, minute, second, microsecond, duration)

Shifts a time by the given Duration.t/0.

Time arithmetic is delegated to Calendar.ISO.shift_time/5.

Arguments

  • hour, minute, second, microsecond form the time to shift.

  • duration is a Duration.t/0.

Returns

  • A four-tuple {hour, minute, second, microsecond} representing the shifted time.

Examples

iex> Calendrical.Julian.shift_time(12, 0, 0, {0, 0}, Duration.new!(hour: 1))
{13, 0, 0, {0, 0}}

valid_date?(year, month, day)

Returns whether the supplied year, month, and day is a valid Julian date.

Arguments

  • year is any Julian year as an integer. The year 0 is not valid (the Julian calendar has no year zero).

  • month is a month in the range 1..12.

  • day is a day-of-month appropriate for the month.

Returns

  • true if the date is valid; otherwise false.

Examples

iex> Calendrical.Julian.valid_date?(2024, 2, 29)
true

iex> Calendrical.Julian.valid_date?(2023, 2, 29)
false

iex> Calendrical.Julian.valid_date?(0, 1, 1)
false

week(year, week)

Returns {:error, :not_defined} because the Julian calendar does not define a week-of-year scheme.

Arguments

  • year is any non-zero Julian year as an integer.

  • week is the requested week number.

Returns

  • {:error, :not_defined}.

Examples

iex> Calendrical.Julian.week(2025, 1)
{:error, :not_defined}

week_of_month(year, month, day)

@spec week_of_month(year(), month(), day()) ::
  {pos_integer(), pos_integer()} | {:error, :not_defined}

Returns {:error, :not_defined} because the Julian calendar does not define a week-of-month scheme.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • {:error, :not_defined}.

Examples

iex> Calendrical.Julian.week_of_month(2025, 1, 1)
{:error, :not_defined}

week_of_year(year, month, day)

@spec week_of_year(year(), month(), day()) :: {:error, :not_defined}

Returns {:error, :not_defined} because the Julian calendar does not define a week-of-year scheme of its own.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • {:error, :not_defined}.

Examples

iex> Calendrical.Julian.week_of_year(2025, 1, 1)
{:error, :not_defined}

year(year)

Returns a Date.Range.t/0 representing the given Julian year.

Arguments

  • year is any non-zero Julian year as an integer.

Returns

Examples

iex> Calendrical.Julian.year(2025)
Date.range(~D[2025-01-01 Calendrical.Julian], ~D[2025-12-31 Calendrical.Julian])

year_of_era(year)

@spec year_of_era(year()) :: {year(), era :: 0..1}

Returns the year and era for the given Julian year.

The Julian calendar has two eras: the current era which starts in year 1 and is defined as era 1; and a second era for years less than 1, defined as era 0.

Arguments

  • year is any non-zero Julian year as an integer.

Returns

  • A two-tuple {year_in_era, era} where era is 0 or 1.

Examples

iex> Calendrical.Julian.year_of_era(2025)
{2025, 1}

iex> Calendrical.Julian.year_of_era(-50)
{50, 0}

year_of_era(year, month, day)

@spec year_of_era(year(), month(), day()) :: {year :: Calendar.year(), era :: 0..1}

Returns the year and era for the Julian date given by year, month, and day.

Arguments

  • year is any non-zero Julian year as an integer.

  • month is a month in the range 1..12.

  • day is a day-of-month.

Returns

  • A two-tuple {year_in_era, era} where era is 0 or 1.

Examples

iex> Calendrical.Julian.year_of_era(2025, 1, 1)
{2025, 1}