Cldr.DateTime.Relative (Cldr Dates & Times v2.23.0)

View Source

Functions to support the string formatting of relative time/datetime numbers.

This module provides formatting of numbers (as integers, floats, Dates or DateTimes) as "ago" or "in" with an appropriate time unit. For example, "2 days ago" or "in 10 seconds"

Summary

Functions

An example implementation of a function to derive an appropriate time unit for a relative time.

Returns a list of the valid unit keys for to_string/2

Returns a {:ok, string} representing a relative time (ago, in) for a given number, Date or Datetime. Returns {:error, reason} when errors are detected.

Returns a string representing a relative time (ago, in) for a given number, Date or Datetime or raises an exception on error.

Functions

derive_unit_from(relative, relative_to, time_difference, atom)

An example implementation of a function to derive an appropriate time unit for a relative time.

Arguments

  • relative, the first argument provided to to_string/3.

  • relative_to the value of option :relative_to provided to to_string/3 or its default value.

  • time_difference is the difference in seconds between relative and relative_to.

  • unit being the requested time unit which may be nil. If nil then the time unit must be derived and the time_difference scaled to that time unit. If specified then the time_difference must be scaled to that time unit.

Returns

  • {relative, unit} where relative is the integer value of the derived and scaled time unit. unit is the derived or given time unit.

Notes

  • In this implementation the time difference is used to derive seconds, minutes, hours, days and weeks. The :month and :year fields of the the relative struct are used to derive months and years.

known_styles()

known_units()

Returns a list of the valid unit keys for to_string/2

Example

iex> Cldr.DateTime.Relative.known_units()
[:day, :fri, :hour, :minute, :mon, :month, :quarter, :sat, :second,
:sun, :thu, :tue, :wed, :week, :year]

scale_relative(time_difference, unit, derive_unit_from \\ %{day: 86400, hour: 3600, minute: 60, month: 2_629_743.83, second: 1, week: 604_800, year: 31_556_926})

Calculates the time span in the given unit from the time given in seconds.

Examples

iex> Cldr.DateTime.Relative.scale_relative(1234, :second)
1234

iex> Cldr.DateTime.Relative.scale_relative(1234, :minute)
21

iex> Cldr.DateTime.Relative.scale_relative(1234, :hour)
0

to_string(relative, backend \\ Cldr.Date.default_backend(), options \\ [])

@spec to_string(
  integer() | float() | Date.t() | DateTime.t(),
  Cldr.backend(),
  Keyword.t()
) ::
  {:ok, String.t()} | {:error, {module(), String.t()}}

Returns a {:ok, string} representing a relative time (ago, in) for a given number, Date or Datetime. Returns {:error, reason} when errors are detected.

Options

  • :locale is the locale in which the binary is formatted. The default is Cldr.get_locale/0

  • :format is the format of the binary. Format may be :default, :narrow or :short.

  • :unit is the time unit for the formatting. The allowable units are :second, :minute, :hour, :day, :week, :month, :year, :mon, :tue, :wed, :thu, :fri, :sat, :sun, :quarter. If no :unit is specified, one will be derived using the :derive_unit_from option.

  • :relative_to is the baseline t:Date/0 or t:Datetime.t/0 from which the difference from relative is calculated when relative is a Date or a DateTime. The default for a Date.t/0 is Date.utc_today/0, for a DateTime.t/0 it is DateTime.utc_now/0.

  • :derive_unit_from is used to derive the most appropriate time unit if none is provided. THere are two ways to specify :derive_unit_from.

    • The first option is a map. The map is required to have the keys :second, :minute, :hour, :day, :week, :month, and :year with the values being the number of seconds below which the key defines the time unit difference. This is the default and its value is:

      %{second: 1, month: 2629743.83, day: 86400, year: 31556926, minute: 60, hour: 3600, week: 604800}

    • The second option is to specify a function reference. The function must take four arguments as described below.

The :derive_unit_from` map

  • Any :derive_unit_from map is first merged into the default map. This means that developers can use the default values and override only specific entries by providing a sparse map.

  • Any entry in the :derive_unit_from map that has a value of nil is ignored. This has the result that any key set to nil will never be represented in the output.

  • Any entry in the :derive_unit_from map that has the value :infinity will always be the largest time unit used to represent the relative time.

The :derive_unit_from function

  • The function must take four arguments:

    • relative, being the first argument to to_string/3.
    • relative_to being the value of option :relative_to or its default value.
    • time_difference being the difference in seconds between relative and relative_to.
    • unit being the requested time unit which may be nil. If nil then the time unit must be derived and the time_difference scaled to that time unit. If specified then the time_difference must be scaled to that time unit.
  • The function must return a tuple of the form {relative, unit} where relative is an integer value and unit is the appropriate time unit atom.

  • See the Cldr.DateTime.Relative.derive_unit_from/4 function for an example.

Examples

iex> Cldr.DateTime.Relative.to_string(-1, MyApp.Cldr)
{:ok, "1 second ago"}

iex> Cldr.DateTime.Relative.to_string(1, MyApp.Cldr)
{:ok, "in 1 second"}

iex> Cldr.DateTime.Relative.to_string(1, MyApp.Cldr, unit: :day)
{:ok, "tomorrow"}

iex> Cldr.DateTime.Relative.to_string(1, MyApp.Cldr, unit: :day, locale: "fr")
{:ok, "demain"}

iex> Cldr.DateTime.Relative.to_string(1, MyApp.Cldr, unit: :day, format: :narrow)
{:ok, "tomorrow"}

iex> Cldr.DateTime.Relative.to_string(1234, MyApp.Cldr, unit: :year)
{:ok, "in 1,234 years"}

iex> Cldr.DateTime.Relative.to_string(1234, MyApp.Cldr, unit: :year, locale: "fr")
{:ok, "dans 1 234 ans"}

iex> Cldr.DateTime.Relative.to_string(31, MyApp.Cldr)
{:ok, "in 31 seconds"}

iex> Cldr.DateTime.Relative.to_string(~D[2017-04-29], MyApp.Cldr, relative_to: ~D[2017-04-26])
{:ok, "in 3 days"}

iex> Cldr.DateTime.Relative.to_string(310, MyApp.Cldr, format: :short, locale: "fr")
{:ok, "dans 5 min"}

iex> Cldr.DateTime.Relative.to_string(310, MyApp.Cldr, format: :narrow, locale: "fr")
{:ok, "+5 min"}

iex> Cldr.DateTime.Relative.to_string 2, MyApp.Cldr, unit: :wed, format: :short, locale: "en"
{:ok, "in 2 Wed."}

iex> Cldr.DateTime.Relative.to_string 1, MyApp.Cldr, unit: :wed, format: :short
{:ok, "next Wed."}

iex> Cldr.DateTime.Relative.to_string -1, MyApp.Cldr, unit: :wed, format: :short
{:ok, "last Wed."}

iex> Cldr.DateTime.Relative.to_string -1, MyApp.Cldr, unit: :wed
{:ok, "last Wednesday"}

iex> Cldr.DateTime.Relative.to_string -1, MyApp.Cldr, unit: :quarter
{:ok, "last quarter"}

iex> Cldr.DateTime.Relative.to_string -1, MyApp.Cldr, unit: :mon, locale: "fr"
{:ok, "lundi dernier"}

iex> Cldr.DateTime.Relative.to_string(~D[2017-04-29], MyApp.Cldr, unit: :ziggeraut)
{:error, {Cldr.DateTime.UnknownTimeUnit,
 "Unknown time unit :ziggeraut.  Valid time units are [:day, :fri, :hour, :minute, :mon, :month, :quarter, :sat, :second, :sun, :thu, :tue, :wed, :week, :year]"}}

to_string!(relative, backend \\ Cldr.Date.default_backend(), options \\ [])

@spec to_string!(
  integer() | float() | Date.t() | DateTime.t(),
  Cldr.backend(),
  Keyword.t()
) ::
  String.t()

Returns a string representing a relative time (ago, in) for a given number, Date or Datetime or raises an exception on error.

Arguments

Options

  • :locale is the locale in which the binary is formatted. The default is Cldr.get_locale/0.

  • :format is the format of the binary. Format may be :default, :narrow or :short. The default is :default.

  • :unit is the time unit for the formatting. The allowable units are :second, :minute, :hour, :day, :week, :month, :year, :mon, :tue, :wed, :thu, :fri, :sat, :sun, :quarter. If no :unit is specified, one will be derived using the :derive_unit_from option.

  • :relative_to is the baseline t:Date/0 or t:Datetime.t/0 from which the difference from relative is calculated when relative is a Date or a DateTime. The default for a Date.t/0 is Date.utc_today/0, for a DateTime.t/0 it is DateTime.utc_now/0.

  • :derive_unit_from is used to derive the most appropriate time unit if none is provided. THere are two ways to specify :derive_unit_from.

    • The first option is a map. The map is required to have the keys :second, :minute, :hour, :day, :week, :month, and :year with the values being the number of seconds below which the key defines the time unit difference. This is the default and its value is:

      %{second: 1, month: 2629743.83, day: 86400, year: 31556926, minute: 60, hour: 3600, week: 604800}

    • The second option is to specify a function reference. The function must take four arguments as described below.

The :derive_unit_from` map

  • Any :derive_unit_from map is first merged into the default map. This means that developers can use the default values and override only specific entries by providing a sparse map.

  • Any entry in the :derive_unit_from map that has a value of nil is ignored. This has the result that any key set to nil will never be represented in the output.

  • Any entry in the :derive_unit_from map that has the value :infinity will always be the largest time unit used to represent the relative time.

The :derive_unit_from function

  • The function must take four arguments:

    • relative, being the first argument to to_string/3.
    • relative_to being the value of option :relative_to or its default value.
    • time_difference being the difference in seconds between relative and relative_to.
    • unit being the requested time unit which may be nil. If nil then the time unit must be derived and the time_difference scaled to that time unit. If specified then the time_difference must be scaled to that time unit.
  • The function must return a tuple of the form {relative, unit} where relative is an integer value and unit is the appropriate time unit atom.

  • See the Cldr.DateTime.Relative.derive_unit_from/4 function for an example.

See to_string/3 for example usage.

unit_from_relative_time(time_difference, unit \\ nil, derive_unit_from \\ %{day: 86400, hour: 3600, minute: 60, month: 2_629_743.83, second: 1, week: 604_800, year: 31_556_926})

Returns an estimate of the appropriate time unit for an integer of a given magnitude of seconds.

Examples

iex> Cldr.DateTime.Relative.unit_from_relative_time(1234)
:minute

iex> Cldr.DateTime.Relative.unit_from_relative_time(12345)
:hour

iex> Cldr.DateTime.Relative.unit_from_relative_time(123456)
:day

iex> Cldr.DateTime.Relative.unit_from_relative_time(1234567)
:week

iex> Cldr.DateTime.Relative.unit_from_relative_time(12345678)
:month

iex> Cldr.DateTime.Relative.unit_from_relative_time(123456789)
:year