diff --git a/CHANGELOG.md b/CHANGELOG.md index 688f28e..454a28d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ **Note that `ex_cldr_dates_times` version 2.18.0 and later are supported on Elixir 1.12 and later only.** +## Cldr_Dates_Times v2.19.2 + +This is the changelog for Cldr_Dates_Times v2.19.2 released on July 9th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_cldr_dates_times/tags) + +### Bug Fixes + +* Reinstate `Cldr.DateTime.Format.date_formats/3` which was incorrectly removed in version 2.19. Version 2.19 made efforts to improve the symmetry of `Cldr.Date`, `Cldr.Time` and `Cldr.DateTime`. Part of that work is to have each of those modules contain the functions `formats/3` and `available_formats/3`. It was not intended at this time that the equivalent functions be removed from `Cldr.DateTime.Format`. Thanks to @tjchambers for the report. Closes #51. + ## Cldr_Dates_Times v2.19.1 This is the changelog for Cldr_Dates_Times v2.19.1 released on July 8th, 2024. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_cldr_dates_times/tags) diff --git a/lib/cldr/date.ex b/lib/cldr/date.ex index ab1e437..d5607f9 100644 --- a/lib/cldr/date.ex +++ b/lib/cldr/date.ex @@ -348,8 +348,7 @@ defmodule Cldr.Date do calendar \\ Cldr.Calendar.default_cldr_calendar(), backend \\ Cldr.Date.default_backend() ) do - backend = Module.concat(backend, DateTime.Format) - backend.date_formats(locale, calendar) + Cldr.DateTime.Format.date_formats(locale, calendar, backend) end @doc """ diff --git a/lib/cldr/date_time.ex b/lib/cldr/date_time.ex index f9fe2e7..ea9b58f 100644 --- a/lib/cldr/date_time.ex +++ b/lib/cldr/date_time.ex @@ -21,6 +21,7 @@ defmodule Cldr.DateTime do alias Cldr.DateTime.Format alias Cldr.LanguageTag + alias Cldr.Locale @format_types [:short, :medium, :long, :full] @default_format_type :medium @@ -101,9 +102,12 @@ defmodule Cldr.DateTime do ## Options - * `:format` is one of `:short`, `:medium`, `:long`, `:full` or a format string or - any of the keys in the map returned by `Cldr.DateTime.Format.date_time_formats/3`. - The default is `:medium`. See [here](README.md#date-time-and-datetime-localization-formats) + * `:format` is one of `:short`, `:medium`, `:long`, `:full`, or a format ID + or a format string. The default is `:medium` for full datetimes (that is, + dates having `:year`, `:month`, `:day`, `:hour`, `:minutes`, `:second` and + `:calendar` fields). The default for partial datetimes is to derive a candidate + format ID from the date and find the best match from the formats returned by + `Cldr.DateTime.available_formats/3`. See [here](README.md#date-time-and-datetime-localization-formats) for more information about specifying formats. * `:date_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined, @@ -249,9 +253,12 @@ defmodule Cldr.DateTime do ## Options - * `:format` is one of `:short`, `:medium`, `:long`, `:full` or a format string or - any of the keys returned by `Cldr.DateTime.Format.date_time_formats/3`. - The default is `:medium`. See [here](README.md#date-time-and-datetime-localization-formats) + * `:format` is one of `:short`, `:medium`, `:long`, `:full`, or a format ID + or a format string. The default is `:medium` for full datetimes (that is, + dates having `:year`, `:month`, `:day`, `:hour`, `:minutes`, `:second` and + `:calendar` fields). The default for partial datetimes is to derive a candidate + format ID from the date and find the best match from the formats returned by + `Cldr.DateTime.available_formats/3`. See [here](README.md#date-time-and-datetime-localization-formats) for more information about specifying formats. * `:style` is either `:at` or `:default`. When set to `:at` the datetime may @@ -321,6 +328,146 @@ defmodule Cldr.DateTime do end end + @doc """ + Returns a map of the standard datetime formats for a given locale and calendar. + + ## Arguments + + * `locale` is any locale returned by `Cldr.known_locale_names/0` + or a `t:Cldr.LanguageTag.t/0`. The default is `Cldr.get_locale/0`. + + * `calendar` is any calendar returned by `Cldr.DateTime.Format.calendars_for/1` + The default is `:gregorian`. + + * `backend` is any module that includes `use Cldr` and therefore + is a `Cldr` backend module. The default is `Cldr.default_backend/0`. + + ## Examples: + + iex> Cldr.DateTime.Format.date_time_formats(:en) + {:ok, %Cldr.DateTime.Formats{ + full: "{1}, {0}", + long: "{1}, {0}", + medium: "{1}, {0}", + short: "{1}, {0}" + }} + + iex> Cldr.DateTime.Format.date_time_formats(:en, :buddhist, MyApp.Cldr) + {:ok, %Cldr.DateTime.Formats{ + full: "{1}, {0}", + long: "{1}, {0}", + medium: "{1}, {0}", + short: "{1}, {0}" + }} + + """ + @spec formats( + Locale.locale_reference(), + Cldr.Calendar.calendar(), + Cldr.backend() + ) :: + {:ok, map()} | {:error, {atom, String.t()}} + + def formats( + locale \\ Cldr.get_locale(), + calendar \\ Cldr.Calendar.default_cldr_calendar(), + backend \\ Cldr.Date.default_backend() + ) do + Cldr.DateTime.Format.date_time_formats(locale, calendar, backend) + end + + @doc """ + Returns a map of the available datetime formats for a + given locale and calendar. + + ## Arguments + + * `locale` is any locale returned by `Cldr.known_locale_names/0` + or a `t:Cldr.LanguageTag.t/0`. The default is `Cldr.get_locale/0`. + + * `calendar` is any calendar returned by `Cldr.DateTime.Format.calendars_for/1` + The default is `:gregorian`. + + * `backend` is any module that includes `use Cldr` and therefore + is a `Cldr` backend module. The default is `Cldr.default_backend/0`. + + ## Examples: + + iex> Cldr.DateTime.available_formats(:en) + {:ok, + %{ + yw: %{ + other: "'week' w 'of' Y", + one: "'week' w 'of' Y", + pluralize: :week_of_year + }, + GyMMMEd: "E, MMM d, y G", + Hms: "HH:mm:ss", + MMMMW: %{ + other: "'week' W 'of' MMMM", + one: "'week' W 'of' MMMM", + pluralize: :week_of_month + }, + E: "ccc", + MMMd: "MMM d", + yMEd: "E, M/d/y", + yQQQ: "QQQ y", + Ehm: %{unicode: "E h:mm a", ascii: "E h:mm a"}, + M: "L", + hm: %{unicode: "h:mm a", ascii: "h:mm a"}, + yM: "M/y", + GyMMMd: "MMM d, y G", + GyMd: "M/d/y G", + Gy: "y G", + Hm: "HH:mm", + EBhms: "E h:mm:ss B", + d: "d", + hms: %{unicode: "h:mm:ss a", ascii: "h:mm:ss a"}, + Ed: "d E", + Ehms: %{unicode: "E h:mm:ss a", ascii: "E h:mm:ss a"}, + EHms: "E HH:mm:ss", + Bh: "h B", + h: %{unicode: "h a", ascii: "h a"}, + Bhms: "h:mm:ss B", + Hmv: "HH:mm v", + hmv: %{unicode: "h:mm a v", ascii: "h:mm a v"}, + yMd: "M/d/y", + ms: "mm:ss", + MMM: "LLL", + y: "y", + Bhm: "h:mm B", + yMMM: "MMM y", + yQQQQ: "QQQQ y", + yMMMEd: "E, MMM d, y", + yMMMM: "MMMM y", + EBhm: "E h:mm B", + Hmsv: "HH:mm:ss v", + yMMMd: "MMM d, y", + MEd: "E, M/d", + EHm: "E HH:mm", + GyMMM: "MMM y G", + hmsv: %{unicode: "h:mm:ss a v", ascii: "h:mm:ss a v"}, + H: "HH", + Md: "M/d", + MMMEd: "E, MMM d", + MMMMd: "MMMM d" + }} + + """ + @spec available_formats( + Locale.locale_reference(), + Cldr.Calendar.calendar(), + Cldr.backend() + ) :: {:ok, map()} | {:error, {atom, String.t()}} + + def available_formats( + locale \\ Cldr.get_locale(), + calendar \\ Cldr.Calendar.default_cldr_calendar(), + backend \\ Cldr.Date.default_backend() + ) do + Format.date_time_available_formats(locale, calendar, backend) + end + defp normalize_options(datetime, backend, []) do {locale, _backend} = Cldr.locale_and_backend_from(nil, backend) number_system = Cldr.Number.System.number_system_from_locale(locale, backend) diff --git a/lib/cldr/format/date_time_format.ex b/lib/cldr/format/date_time_format.ex index 15e33c6..41376ad 100644 --- a/lib/cldr/format/date_time_format.ex +++ b/lib/cldr/format/date_time_format.ex @@ -180,6 +180,56 @@ defmodule Cldr.DateTime.Format do backend.hour_format(locale) end + @doc """ + Returns a map of the standard date formats for a given + locale and calendar. + + ### Arguments + + * `locale` is any locale returned by `Cldr.known_locale_names/0` + or a `t:Cldr.LanguageTag.t/0`. The default is `Cldr.get_locale/0`. + + * `calendar` is any calendar returned by `Cldr.DateTime.Format.calendars_for/1` + The default is `:gregorian`. + + * `backend` is any module that includes `use Cldr` and therefore + is a `Cldr` backend module. The default is `Cldr.default_backend/0`. + + ### Examples: + + iex> Cldr.DateTime.Format.date_formats(:en, :gregorian, MyApp.Cldr) + {:ok, %Cldr.Date.Formats{ + full: "EEEE, MMMM d, y", + long: "MMMM d, y", + medium: "MMM d, y", + short: "M/d/yy" + }} + + iex> Cldr.DateTime.Format.date_formats(:en, :buddhist, MyApp.Cldr) + {:ok, %Cldr.Date.Formats{ + full: "EEEE, MMMM d, y G", + long: "MMMM d, y G", + medium: "MMM d, y G", + short: "M/d/y GGGGG" + }} + + """ + @spec date_formats( + Locale.locale_reference(), + Cldr.Calendar.calendar(), + Cldr.backend() + ) :: + {:ok, Cldr.DateTime.Format.standard_formats()} | {:error, {atom, String.t()}} + + def date_formats( + locale \\ Cldr.get_locale(), + calendar \\ Cldr.Calendar.default_cldr_calendar(), + backend \\ Cldr.Date.default_backend() + ) do + backend = Module.concat(backend, DateTime.Format) + backend.date_formats(locale, calendar) + end + @doc """ Returns a map of the standard time formats for a given locale and calendar. diff --git a/lib/cldr/time.ex b/lib/cldr/time.ex index 03d4e62..2bd7c58 100644 --- a/lib/cldr/time.ex +++ b/lib/cldr/time.ex @@ -412,8 +412,7 @@ defmodule Cldr.Time do calendar \\ Cldr.Calendar.default_cldr_calendar(), backend \\ Cldr.Date.default_backend() ) do - backend = Module.concat(backend, DateTime.Format) - backend.time_formats(locale, calendar) + Cldr.DateTime.Format.time_formats(locale, calendar, backend) end @doc """ diff --git a/mix.exs b/mix.exs index fb9113d..7b3c625 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Cldr.DatesTimes.Mixfile do use Mix.Project - @version "2.19.1" + @version "2.19.2" def project do [ diff --git a/mix/for_dialyzer.ex b/mix/for_dialyzer.ex index 63126d0..dfcc9c5 100644 --- a/mix/for_dialyzer.ex +++ b/mix/for_dialyzer.ex @@ -15,6 +15,16 @@ defmodule Cldr.DatesTimes.Dialyzer do {:ok, %{medium: _format_dt}} = MyApp.Cldr.DateTime.Format.time_formats(:en) end + def formats do + {:ok, _} = Cldr.Date.formats() + {:ok, _} = Cldr.Time.formats() + {:ok, _} = Cldr.DateTime.formats() + + {:ok, _} = Cldr.Date.available_formats() + {:ok, _} = Cldr.Time.available_formats() + {:ok, _} = Cldr.DateTime.available_formats() + end + def format do _ = Cldr.DateTime.Format.calendars_for(:en, MyApp.Cldr) _ = Cldr.DateTime.Format.calendars_for("en", MyApp.Cldr) diff --git a/test/cldr_dates_times_test.exs b/test/cldr_dates_times_test.exs index 7ffc9cb..d7a5a6d 100644 --- a/test/cldr_dates_times_test.exs +++ b/test/cldr_dates_times_test.exs @@ -161,4 +161,14 @@ defmodule Cldr.DatesTimes.Test do assert {:ok, "July 7, 2024, 9:36:00 PM UTC"} = Cldr.DateTime.to_string(datetime, format: :long, style: :default) end + + test "Symmetry of the format/3 and available_format/3 functions for Date, Time and DateTime" do + assert {:ok, _} = Cldr.Date.formats() + assert {:ok, _} = Cldr.Time.formats() + assert {:ok, _} = Cldr.DateTime.formats() + + assert {:ok, _} = Cldr.Date.available_formats() + assert {:ok, _} = Cldr.Time.available_formats() + assert {:ok, _} = Cldr.DateTime.available_formats() + end end