elixir-cldr / cldr_dates_times

Date & times formatting functions for the Common Locale Data Repository (CLDR) package https://github.com/elixir-cldr/cldr
Other
69 stars 13 forks source link

Question regarding CLDR date-time combined formats #41

Closed jueberschlag closed 1 year ago

jueberschlag commented 1 year ago

Hi,

I was looking for a way to format a date in the following format in English and French :

By doing some tests and browsing the code and the CLDR specifications I found this chapter regarding date-time combine formats: https://cldr.unicode.org/translation/date-time/date-time-patterns#h.x7ca7qwzh4m

Especially a paragraph that says:

The determination of which to use by developers using CLDR data is normally based on the date style, for example:
If the date has a full month and weekday name, use the full combining pattern.
If the date has numeric month, use the short version of the combining pattern.

I am using ex_cldr_dates_times version 2.13.2 and ex_cldr version 2.37.2 which should be based upon CLDR version 43.

In this case, should this library use the -atTime format if the date has a full month and weekday name?

If needed I'll be more than happy to have a look and try to fix this in both the Cldr.DateTime.Format.Backend and Cldr.DateTime.Formatter.Backend modules.

Thanks

kipcole9 commented 1 year ago

Thanks for raising this issue, it's been on the "to do" list too long.

As of a3edd42 I've added the function MyApp.Cldr.DateTime.date_time_at_formats/2 so that the formats are now included in the backend. I've also added Cldr.DateTime.date_time_at_formats/2.

As for the formatting part, I'm thinking to add style: :at as an option to Cldr.DateTime.to_string/2. This is a little different to TR35 which suggests the default should be the "at" format. However that would be a breaking change I'd prefer to avoid.

I'm on a long flight today so I should be able to wrap this up by end of Saturday my time (UTC+8 when I land).

Would this approach work for you?

kipcole9 commented 1 year ago

I managed to get an implementation done before my flight. Here are some examples:

iex> date_time = ~U[2023-09-08 15:50:00Z]

iex> Cldr.DateTime.to_string(date_time, format: :full, style: :at)
{:ok, "Friday, September 8, 2023 at 3:50:00 PM GMT"}

iex> Cldr.DateTime.to_string(date_time, format: :long, style: :at)
{:ok, "September 8, 2023 at 3:50:00 PM UTC"}

iex> Cldr.DateTime.to_string(date_time, format: :full, style: :at, locale: :fr)
{:ok, "vendredi 8 septembre 2023 à 15:50:00 UTC"}

iex> Cldr.DateTime.to_string(date_time, format: :long, style: :at, locale: :fr)
{:ok, "8 septembre 2023 à 15:50:00 UTC"}

The formats are, of course, based upon CLDR data. They can be introspected with:

iex> MyApp.Cldr.DateTime.Format.date_time_at_formats(:en)
{:ok,
 %Cldr.DateTime.Formats{
   short: "{1}, {0}",
   medium: "{1}, {0}",
   long: "{1} 'at' {0}",
   full: "{1} 'at' {0}"
 }}

iex> MyApp.Cldr.DateTime.Format.date_time_at_formats(:fr)
{:ok,
 %Cldr.DateTime.Formats{
   short: "{1} {0}",
   medium: "{1}, {0}",
   long: "{1} 'à' {0}",
   full: "{1} 'à' {0}"
 }}

Feedback most welcome.

kipcole9 commented 1 year ago

One of the ideas I've been toying with for a while has been to separately specify the format of the date part and the time part.

Instead of format: :long which means both the date and the time are formatted using their respective :long format it would be possible to say format: [:long, :medium] meaning :long for the date and :medium for the time.

WDYT?

jueberschlag commented 1 year ago

Thanks for these changes ! I like the style: :at option to avoid a breaking change.

Regarding your idea to separate the date and time formats, I don't have your experience with CLDR data but how would you handle the combination of a :full date format with a :medium time format? From what I see in CLDR data for the :en locale, the combination also differs based on the format: https://www.unicode.org/cldr/cldr-aux/charts/28/summary/en.html#1717

kipcole9 commented 1 year ago

The way the formats are packaged in the data there are three ways to format a date (same approach is used for numbers and units of measures):

Not surprisingly, the predefined formats are most often used because of the locale-independence.

Since the formats for date times are of the form "{1} 'at' {0}" you can infer that the the date and time are formatted separately then combined. Which is why adding format: [:full, :short] is a really east thing to implement - if it’s of any value.

jueberschlag commented 1 year ago

Because of the new style: :at option I would have no need of a format such as format: [:full, :short] but I can see why others may need it.

Thanks for the explanation but in this case I still don't know how you would determine which date-time combination format: if you use the date format (:long) the format is {1} 'at' {0} and if you use te time format (:short) then the format is {1}, {0}. Or maybe you were thinking of always using {1} 'at' {0}?

kipcole9 commented 1 year ago

Because of the new style: :at option I would have no need of a format such as format: [:full, :short]

Understood, thanks for the feedback.

Just to close this out, your comment made me realise I didn't fully explain that date times are composed from separately formatted dates and formatted times. If we look at the :short, :medium, etc for dates and for times we see the following. Which I hope closes the loop on how date time formats are constructed.

iex> MyApp.Cldr.DateTime.Format.date_formats(:fr)
{:ok,
 %Cldr.Date.Formats{
   short: "dd/MM/y",
   medium: "d MMM y",
   long: "d MMMM y",
   full: "EEEE d MMMM y"
 }}

iex> MyApp.Cldr.DateTime.Format.time_formats(:fr)
{:ok,
 %Cldr.Time.Formats{
   short: "HH:mm",
   medium: "HH:mm:ss",
   long: "HH:mm:ss z",
   full: "HH:mm:ss zzzz"
 }}
kipcole9 commented 1 year ago

I've published ex_cldr_dates_times version 2.15.0 with the following changelog entry:

Deprecations

Enhancements