Formats date and time intervals as localized strings.
Interval formats produce strings like "Jan 10 – 12, 2008" from two dates, rather than repeating "Jan 10, 2008 – Jan 12, 2008". The format is selected based on the greatest calendar field difference between the start and end values.
Summary
Functions
Returns the locale-independent date interval style configurations.
Returns the greatest calendar field difference between two dates or datetimes.
Splits an interval format string into [left, right] halves
at the point where a format character repeats.
Formats a date, time, or datetime interval into typed parts, mirroring ECMA-402's formatRangeToParts.
Same as to_parts/3 but raises on error.
Formats a date interval as a localized string.
Same as to_string/3 but raises on error.
Functions
@spec date_styles() :: %{
month: %{short: :M, medium: :MMM, long: :MMM, full: :MMM},
month_and_day: %{short: :Md, medium: :MMMd, long: :MMMEd, full: :MMMEd},
year_and_month: %{short: :yM, medium: :yMMM, long: :yMMMM, full: :yMMMM}
}
Returns the locale-independent date interval style configurations.
Only the non-default :style options (:month,
:month_and_day, :year_and_month) appear here. The default
:date style is resolved per-locale, mirroring
Localize.Date.to_string/2's style → skeleton mapping for that
locale.
Examples
iex> Localize.Interval.date_styles()
%{
month: %{short: :M, full: :MMM, long: :MMM, medium: :MMM},
month_and_day: %{short: :Md, full: :MMMEd, long: :MMMEd, medium: :MMMd},
year_and_month: %{short: :yM, full: :yMMMM, long: :yMMMM, medium: :yMMM}
}
@spec greatest_difference(map(), map()) :: {:ok, :y | :M | :d | :H | :m} | {:error, Exception.t()}
Returns the greatest calendar field difference between two dates or datetimes.
Arguments
fromis a date or datetime map.tois a date or datetime map.
Returns
{:ok, field}where field is:y,:M,:d,:H, or:m.{:error, %Localize.NoPracticalDifferenceError{}}if the values are equal at every field considered.
Examples
iex> Localize.Interval.greatest_difference(~D[2022-04-22], ~D[2022-04-27])
{:ok, :d}
iex> Localize.Interval.greatest_difference(~D[2021-12-31], ~D[2022-01-01])
{:ok, :y}
@spec split_interval(String.t()) :: {:ok, [String.t()]} | {:error, Exception.t()}
Splits an interval format string into [left, right] halves
at the point where a format character repeats.
Examples
iex> Localize.Interval.split_interval("MMM d – d")
{:ok, ["MMM d – ", "d"]}
@spec to_parts(map(), map(), Keyword.t()) :: {:ok, [%{type: atom(), value: String.t(), source: atom()}]} | {:error, Exception.t()}
Formats a date, time, or datetime interval into typed parts, mirroring ECMA-402's formatRangeToParts.
The parts concatenate to exactly the string to_string/3 produces with the same options. Every part carries a :source key: :start_range for parts of the interval start, :end_range for parts of the interval end, and :shared for the separators between them. When the endpoints have no practical difference the single formatted value carries source :shared throughout.
Unlike to_string/3, open intervals (a nil endpoint) are not supported — both endpoints are required, matching the JS API.
Arguments
fromis aDate,Time,DateTime,NaiveDateTime, or compatible map for the interval start.tois a value of the same kind for the interval end.optionsis a keyword list of options. Seeto_string/3.
Returns
{:ok, parts}wherepartsis a list of%{type: atom(), value: String.t(), source: atom()}maps.{:error, exception}on failure or when an endpoint isnil.
Examples
iex> Localize.Interval.to_parts(~D[2022-04-22], ~D[2022-04-25], locale: :en)
{:ok,
[
%{type: :month, value: "Apr", source: :start_range},
%{type: :literal, value: " ", source: :start_range},
%{type: :day, value: "22", source: :start_range},
%{type: :literal, value: " – ", source: :shared},
%{type: :day, value: "25", source: :end_range},
%{type: :literal, value: ", ", source: :end_range},
%{type: :year, value: "2022", source: :end_range}
]}
@spec to_parts!(map(), map(), Keyword.t()) :: [ %{type: atom(), value: String.t(), source: atom()} ]
Same as to_parts/3 but raises on error.
Arguments
fromis the interval start.tois the interval end.optionsis a keyword list of options. Seeto_parts/3.
Returns
- A list of
%{type: atom(), value: String.t(), source: atom()}maps.
Raises
- Raises an exception if the interval cannot be decomposed into parts.
Examples
iex> Localize.Interval.to_parts!(~D[2022-04-22], ~D[2022-04-25], locale: :en) |> length()
7
@spec to_string(map() | nil, map() | nil, Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}
Formats a date interval as a localized string.
Arguments
Options
:localeis a locale identifier. The default is:en.:formatis:short,:medium, or:long. The default is:medium.:styleis:date,:month,:month_and_day, or:year_and_month. The default is:date.
Returns
{:ok, formatted_string}on success.{:error, exception}on failure.
Examples
iex> {:ok, result} = Localize.Interval.to_string(~D[2022-04-22], ~D[2022-04-25], locale: :en)
iex> String.contains?(result, "Apr")
true
iex> {:ok, result} = Localize.Interval.to_string(~D[2022-01-15], ~D[2022-03-20], locale: :en)
iex> String.contains?(result, "Jan") and String.contains?(result, "Mar")
true
Same as to_string/3 but raises on error.
Options
See to_string/3 for the supported options.
Examples
iex> Localize.Interval.to_string!(~D[2022-04-22], ~D[2022-04-25], locale: :en)
"Apr 22 – 25, 2022"
iex> Localize.Interval.to_string!(~D[2022-01-15], ~D[2022-03-20], locale: :en)
"Jan 15 – Mar 20, 2022"