Calendar behaviour

This module defines the responsibilities for working with calendars, dates, times and datetimes in Elixir.

Currently it defines types and the minimal implementation for a calendar behaviour in Elixir. The goal of the Calendar features in Elixir is to provide a base for interoperability instead of full-featured datetime API.

For the actual date, time and datetime structures, see Date, Time, NaiveDateTime and DateTime.

Note the year, month, day, etc. designations are overspecified (i.e. an integer instead of 1..12 for months) because different calendars may have a different number of days per month, months per year and so on.

Summary

Types

calendar()

A calendar implementation

date()

Any map/struct that contains the date fields

datetime()

Any map/struct that contains the datetime fields

day()
day_fraction()

The internal time format is used when converting between calendars

hour()
iso_days()

The internal date format that is used when converting between calendars

microsecond()

Microseconds with stored precision

minute()
month()
naive_datetime()

Any map/struct that contains the naive_datetime fields

second()
std_offset()

The time zone standard offset in seconds (not zero in summer times)

time()

Any map/struct that contains the time fields

time_zone()

The time zone ID according to the IANA tz database (e.g. Europe/Zurich)

utc_offset()

The time zone UTC offset in seconds

year()
zone_abbr()

The time zone abbreviation (e.g. CET or CEST or BST etc.)

Functions

compatible_calendars?(calendar, calendar)

Returns true if two calendars have the same moment of starting a new day, false otherwise

truncate(microsecond_tuple, atom)

Returns a microsecond tuple truncated to a given precision (:microsecond, :millisecond or :second)

Callbacks

date_to_string(year, month, day)

Converts the date into a string according to the calendar

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

Converts the datetime (with time zone) into a string according to the calendar

day_of_week(year, month, day)

Calculates the day of the week from the given year, month, and day

day_rollover_relative_to_midnight_utc()

Define the rollover moment for the given calendar

days_in_month(year, month)

Returns how many days there are in the given year-month

leap_year?(year)

Returns true if the given year is a leap year

naive_datetime_from_iso_days(iso_days)

Converts t:iso_days to the Calendar’s datetime format

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

Converts the given datetime (with time zone) into the t:iso_days format

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

Converts the datetime (without time zone) into a string according to the calendar

time_from_day_fraction(day_fraction)

Converts t:day_fraction to the Calendar’s time format

time_to_day_fraction(hour, minute, second, microsecond)

Converts the given time to the t:day_fraction format

time_to_string(hour, minute, second, microsecond)

Converts the time into a string according to the calendar

valid_date?(year, month, day)

Should return true if the given date describes a proper date in the calendar

valid_time?(hour, minute, second, microsecond)

Should return true if the given time describes a proper time in the calendar

Types

calendar()

calendar() :: module()

A calendar implementation

date()

date() :: %{
  optional(any()) => any(),
  :calendar => calendar(),
  :year => year(),
  :month => month(),
  :day => day()
}

Any map/struct that contains the date fields

datetime()

datetime() :: %{
  optional(any()) => any(),
  :calendar => calendar(),
  :year => year(),
  :month => month(),
  :day => day(),
  :hour => hour(),
  :minute => minute(),
  :second => second(),
  :microsecond => microsecond(),
  :time_zone => time_zone(),
  :zone_abbr => zone_abbr(),
  :utc_offset => utc_offset(),
  :std_offset => std_offset()
}

Any map/struct that contains the datetime fields

day()

day() :: integer()

day_fraction()

day_fraction() ::
  {parts_in_day :: non_neg_integer(), parts_per_day :: pos_integer()}

The internal time format is used when converting between calendars.

It represents time as a fraction of a day (starting from midnight). parts_in_day specifies how much of the day is already passed, while parts_per_day signifies how many parts there fit in a day.

hour()

hour() :: integer()

iso_days()

iso_days() :: {days :: integer(), day_fraction()}

The internal date format that is used when converting between calendars.

This is the number of days including the fractional part that has passed of the last day since 0000-01-01+00:00T00:00.00000 in ISO 8601 notation (also known as midnight 1 January BC 1 of the proleptic Gregorian calendar).

The parts_per_day represent how many subparts the current day is subdivided in (for different calendars, picking a different parts_per_day might make sense). The parts_in_day represents how many of these parts_per_day have passed in the last day.

microsecond()

microsecond() :: {0..999_999, 0..6}

Microseconds with stored precision.

The precision represents the number of digits that must be used when representing the microseconds to external format. If the precision is 0, it means microseconds must be skipped.

minute()

minute() :: integer()

month()

month() :: integer()

naive_datetime()

naive_datetime() :: %{
  optional(any()) => any(),
  :calendar => calendar(),
  :year => year(),
  :month => month(),
  :day => day(),
  :hour => hour(),
  :minute => minute(),
  :second => second(),
  :microsecond => microsecond()
}

Any map/struct that contains the naive_datetime fields

second()

second() :: integer()

std_offset()

std_offset() :: integer()

The time zone standard offset in seconds (not zero in summer times)

time()

time() :: %{
  optional(any()) => any(),
  :hour => hour(),
  :minute => minute(),
  :second => second(),
  :microsecond => microsecond()
}

Any map/struct that contains the time fields

time_zone()

time_zone() :: String.t()

The time zone ID according to the IANA tz database (e.g. Europe/Zurich)

utc_offset()

utc_offset() :: integer()

The time zone UTC offset in seconds

year()

year() :: integer()

zone_abbr()

zone_abbr() :: String.t()

The time zone abbreviation (e.g. CET or CEST or BST etc.)

Functions

compatible_calendars?(calendar, calendar)

compatible_calendars?(Calendar.calendar(), Calendar.calendar()) :: boolean()

Returns true if two calendars have the same moment of starting a new day, false otherwise.

If two calendars are not compatible, we can only convert datetimes and times between them. If they are compatible, this means that we can also convert dates as well as naive datetimes between them.

truncate(microsecond_tuple, atom)

truncate(Calendar.microsecond(), :microsecond | :millisecond | :second) ::
  Calendar.microsecond()

Returns a microsecond tuple truncated to a given precision (:microsecond, :millisecond or :second).

Callbacks

date_to_string(year, month, day)

date_to_string(year(), month(), day()) :: String.t()

Converts the date into a string according to the calendar.

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

datetime_to_string(
  year(),
  month(),
  day(),
  hour(),
  minute(),
  second(),
  microsecond(),
  time_zone(),
  zone_abbr(),
  utc_offset(),
  std_offset()
) :: String.t()

Converts the datetime (with time zone) into a string according to the calendar.

day_of_week(year, month, day)

day_of_week(year(), month(), day()) :: non_neg_integer()

Calculates the day of the week from the given year, month, and day.

day_rollover_relative_to_midnight_utc()

day_rollover_relative_to_midnight_utc() :: day_fraction()

Define the rollover moment for the given calendar.

This is the moment, in your calendar, when the current day ends and the next day starts.

The result of this function is used to check if two calendars rollover at the same time of day. If they do not, we can only convert datetimes and times between them. If they do, this means that we can also convert dates as well as naive datetimes between them.

This day fraction should be in its most simplified form possible, to make comparisons fast.

Examples

  • If, in your Calendar, a new day starts at midnight, return {0, 1}.
  • If, in your Calendar, a new day starts at sunrise, return {1, 4}.
  • If, in your Calendar, a new day starts at noon, return {1, 2}.
  • If, in your Calendar, a new day starts at sunset, return {3, 4}.

days_in_month(year, month)

days_in_month(year(), month()) :: day()

Returns how many days there are in the given year-month.

leap_year?(year)

leap_year?(year()) :: boolean()

Returns true if the given year is a leap year.

A leap year is a year of a longer length than normal. The exact meaning is up to the calendar. A calendar must return false if it does not support the concept of leap years.

naive_datetime_from_iso_days(iso_days)

naive_datetime_from_iso_days(iso_days()) ::
  {year(), month(), day(), hour(), minute(), second(), microsecond()}

Converts t:iso_days to the Calendar’s datetime format.

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

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

Converts the given datetime (with time zone) into the t:iso_days format.

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

naive_datetime_to_string(
  year(),
  month(),
  day(),
  hour(),
  minute(),
  second(),
  microsecond()
) :: String.t()

Converts the datetime (without time zone) into a string according to the calendar.

time_from_day_fraction(day_fraction)

time_from_day_fraction(day_fraction()) ::
  {hour(), minute(), second(), microsecond()}

Converts t:day_fraction to the Calendar’s time format.

time_to_day_fraction(hour, minute, second, microsecond)

time_to_day_fraction(hour(), minute(), second(), microsecond()) ::
  day_fraction()

Converts the given time to the t:day_fraction format.

time_to_string(hour, minute, second, microsecond)

time_to_string(hour(), minute(), second(), microsecond()) :: String.t()

Converts the time into a string according to the calendar.

valid_date?(year, month, day)

valid_date?(year(), month(), day()) :: boolean()

Should return true if the given date describes a proper date in the calendar.

valid_time?(hour, minute, second, microsecond)

valid_time?(hour(), minute(), second(), microsecond()) :: boolean()

Should return true if the given time describes a proper time in the calendar.

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.6.6/Calendar.html