Packages
ex_cldr_dates_times
2.25.2
2.25.6
2.25.5
2.25.4
2.25.3
2.25.2
2.25.1
2.25.0
2.24.2
2.24.1
2.24.0
2.23.0
2.22.0
2.21.0
2.20.3
2.20.2
2.20.0
2.19.2
2.19.1
2.19.0
retired
2.18.1
2.18.0
2.17.1
2.17.0
2.16.0
2.15.0
2.14.3
2.14.2
2.14.1
2.14.0
2.13.3
2.13.2
2.13.1
2.13.0
2.12.0
2.11.0
2.10.2
2.10.1
2.10.0
2.10.0-rc.3
2.10.0-rc.2
2.10.0-rc.1
2.10.0-rc.0
2.9.4
2.9.3
2.9.2
2.9.1
2.9.0
2.8.0
2.7.2
2.7.1
retired
2.7.0
2.7.0-rc.0
2.6.4
2.6.3
2.6.2
2.6.1
retired
2.6.0
2.6.0-rc.0
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.4.0
2.4.0-rc.0
2.3.0
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.2
2.0.1
2.0.0
1.4.0
1.3.1
1.3.0
1.2.1
1.2.0
1.0.1
1.0.0
1.0.0-rc.1
1.0.0-rc.0
retired
0.3.3
0.3.2
retired
0.3.1
retired
0.3.0
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Date, Time and DateTime localization, internationalization and formatting functions using the Common Locale Data Repository (CLDR).
Current section
Files
Jump to
Current section
Files
lib/cldr/backend/formatter.ex
defmodule Cldr.DateTime.Formatter.Backend do
@moduledoc false
def define_date_time_formatter_module(config) do
backend = config.backend
config = Macro.escape(config)
module = inspect(__MODULE__)
quote bind_quoted: [config: config, backend: backend, module: module] do
defmodule DateTime.Formatter do
@moduledoc false
if Cldr.Config.include_module_docs?(config.generate_docs) do
@moduledoc """
Implements the compilation and execution of
date, time and datetime formats.
"""
end
alias Cldr.DateTime.Format.Compiler
alias Cldr.DateTime.Formatter
alias Cldr.Number
@doc """
Returns the formatted and localised date, time or datetime
for a given `Date`, `Time`, `DateTime` or struct with the
appropriate fields.
## Arguments
* `date` is a `Date`, `Time`, `DateTime` or other struct that
contains the required date and time fields.
* `format` is a valid format string, for example `yy/MM/dd hh:MM`
* `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `t:Cldr.LanguageTag.t/0` struct. The default is `Cldr.get_locale/0`
* `options` is a keyword list of options.
## Options
* `:number_system`. The resulting formatted and localised date/time
string will be transliterated into this number system. Number system
is anything returned from `#{inspect(backend)}.Number.System.number_systems_for/1`
*NOTE* This function is called by `Cldr.Date.to_string/2`, `Cldr.Time.to_string/2`
and `Cldr.DateTime.to_string/2` which is the preferred API.
## Examples
iex> #{inspect(__MODULE__)}.format(~U[2017-09-03 10:23:00.0Z], "yy/MM/dd hh:MM", "en")
{:ok, "17/09/03 10:09"}
"""
@spec format(
Cldr.Calendar.any_date_time(),
String.t(),
Cldr.Locale.locale_reference(),
Keyword.t()
) :: {:ok, String.t()} | {:error, {module(), String.t()}}
def format(date, format, locale \\ Cldr.get_locale(), options \\ [])
# Insert generated functions for each locale and format here which
# means that the lexing is done at compile time not runtime
# which improves performance quite a bit.
for format <- Cldr.DateTime.Format.format_list(config) do
case Compiler.compile(format, backend, Cldr.DateTime.Formatter.Backend) do
{:ok, transforms} ->
def format(date, unquote(Macro.escape(format)) = f, locale, options) do
format_transforms(date, f, unquote(transforms), locale, options)
end
{:error, message} ->
raise Cldr.FormatCompileError,
"#{message} compiling date format: #{inspect(format)}"
end
end
# This is the format function that is executed if the supplied format
# has not otherwise been precompiled in the code above. Since this function
# has to tokenize, compile and then interpret the format string
# there is a performance penalty.
def format(date, format, locale, options) do
case Compiler.tokenize(format) do
{:ok, tokens, _} ->
transforms = apply_transforms(tokens, date, locale, options)
format_transforms(date, format, transforms, locale, options)
other ->
other
end
end
@doc false
def format_transforms(date, format, transforms, locale, options) do
number_system =
number_system(format, options)
formatted =
Enum.reduce_while(transforms, "", fn
{:error, reason}, acc -> {:halt, {:error, reason}}
string, acc when is_binary(string) -> {:cont, acc <> string}
number, acc when is_number(number) -> {:cont, acc <> to_string(number)}
list, acc when is_list(list) -> {:cont, acc <> Enum.join(list)}
end)
case formatted do
{:error, reason} ->
{:error, reason}
string ->
transliterated = transliterate(string, locale, number_system)
{:ok, transliterated}
end
end
# Return the number system that is applied to the whole
# formatted string at the end of formatting
defp number_system(%{number_system: %{all: number_system}}, options) do
number_system
end
defp number_system(_format, options) do
options[:number_system]
end
# Return the map that drives number system transliteration
# for individual formatting codes.
defp format_number_systems(%{number_system: number_systems}) do
number_systems
end
defp format_number_systems(_format) do
%{}
end
# Execute the transformation pipeline which does the
# actual formatting
defp apply_transforms(tokens, date, locale, options) do
Enum.map(tokens, fn {token, _line, count} ->
apply(Cldr.DateTime.Formatter, token, [date, count, locale, unquote(backend), options])
end)
end
defp transliterate(formatted, _locale, nil) do
formatted
end
defp transliterate(formatted, _locale, :latn) do
formatted
end
transliterator = Module.concat(backend, :"Number.Transliterate")
defp transliterate(formatted, locale, number_system) do
with {:ok, number_system} <-
Number.System.system_name_from(number_system, locale, unquote(backend)) do
unquote(transliterator).transliterate_digits(formatted, :latn, number_system)
end
end
defp format_errors(list) do
errors =
list
|> Enum.filter(fn
{:error, _reason} -> true
_ -> false
end)
|> Enum.map(fn {:error, reason} -> reason end)
if Enum.empty?(errors), do: nil, else: errors
end
# Compile the formats used for timezones GMT format
def gmt_tz_format(locale, offset, options \\ [])
for locale_name <- Cldr.Locale.Loader.known_locale_names(config) do
{:ok, gmt_format} = Cldr.DateTime.Format.gmt_format(locale_name, backend)
{:ok, gmt_zero_format} = Cldr.DateTime.Format.gmt_zero_format(locale_name, backend)
{:ok, {pos_format, neg_format}} = Cldr.DateTime.Format.hour_format(locale_name, backend)
{:ok, pos_transforms} =
Compiler.compile(pos_format, backend, Cldr.DateTime.Formatter.Backend)
{:ok, neg_transforms} =
Compiler.compile(neg_format, backend, Cldr.DateTime.Formatter.Backend)
def gmt_tz_format(
%LanguageTag{cldr_locale_name: unquote(locale_name)},
%{hour: 0, minute: 0},
_options
) do
unquote(gmt_zero_format)
end
def gmt_tz_format(
%LanguageTag{cldr_locale_name: unquote(locale_name)} = locale,
%{hour: hour, minute: _minute} = date,
options
)
when hour >= 0 do
unquote(pos_transforms)
|> Cldr.DateTime.Format.gmt_format_type(options[:format] || :long)
|> Cldr.Substitution.substitute(unquote(gmt_format))
|> Enum.join()
end
def gmt_tz_format(
%LanguageTag{cldr_locale_name: unquote(locale_name)} = locale,
%{hour: _hour, minute: _minute} = date,
options
) do
unquote(neg_transforms)
|> Cldr.DateTime.Format.gmt_format_type(options[:format] || :long)
|> Cldr.Substitution.substitute(unquote(gmt_format))
|> Enum.join()
end
end
end
end
end
end