Closed jmoldrich2b closed 1 year ago
@jmoldrich2b thanks for the suggestion! There are parts of the CLDR specification and data that are not yet exposed in the ex_cldr
libs, typically because matching the spec to an implementation isn't always obvious. But I understand the ask and it makes sense to me. In part because as you say, for date/times the formatting is the date part and then the time part.
I won't be able to investigate very fully until the weekend but I'll get back to you after then if there is any path forward that can make this happen without breaking everything else.
Thanks again, much appreciated.
Thank you for the prompt reply! As I have a working solution there's no urgency from my end, but looking forward to seeing what you come up with (and using it).
p.s., I was accidentally logged in to a different account when I posted
@jarrodmoldrich sorry for taking a long time to get to this. After review I don't see a practical way to do what you're after using format code (like :medium
). I think the simplest way forward might be to use your own format string. Using your example:
iex> MyApp.Cldr.DateTime.Interval.to_string ~U[2022-04-22 02:00:00Z], ~U[2022-04-22 03:00:00Z],
...> format: "MMM d, y, hh:mm a - hh:mm a"
{:ok, "Apr 22, 2022, 02:00 AM - 03:00 AM"}
To make deciding which format string to use I have published ex_cldr_dates_times version 2.12.0 that exposes the public function Cldr.DateTime.Interval.greatest_difference/2
that will return the format code of the greatest difference. That will allow differentiating amongst interval formats without having to dive deep into formatting yourself.
iex> Cldr.DateTime.Interval.greatest_difference ~U[2022-04-22 02:00:00Z], ~U[2022-04-22 03:00:00Z]
{:ok, :H}
Hopefully that give you an easier way forward? Let me know if that sparks any better ideas? You've been a long way down the rabbit hole of the code!
Thanks for looking into this!
I think the simplest way forward might be to use your own format string.
I think that's basically what I'm doing in my code snippet, except I'm building the format strings from the patterns provided by your library. This approach could be generalised to find a 'mixed format' date time:
fun date_time_format(dt_format, d_format, t_format) do
# get formats
{:ok, dt_formats} = BackEnd.Cldr.DateTime.Format.date_time_formats("en")
{:ok, d_formats} = BackEnd.Cldr.DateTime.Format.date_formats("en")
{:ok, t_formats} = BackEnd.Cldr.DateTime.Format.time_formats("en")
# select formats
dt_format = Map.fetch!(dt_formats, dt_format)
d_format = Map.fetch!(d_formats, d_format)
t_format = Map.fetch!(t_formats, t_format)
# combine formats
template = Cldr.Substitution.parse(dt_format)
Cldr.Substitution.substitute([t_format, d_format], template)
|> IO.iodata_to_binary()
end
So for the from
and to
in the interval it could either use the result of date_time_format(..)
or simply use the appropriate time format for the to
depending on the result of greatest_difference(..)
Passing the format triplet down might be polluting Interval
module with unnecessary complexity, but even having just this utility function to create blended date time formats could be a useful.
I've been very tardy on this but am getting back to it now.
I've pushed some commits that I believe provide the functionality you are looking for (finally!). I need to add some tests before I can publish but you're welcome to try it out from Github now. Here are a couple of examples:
iex> MyApp.Cldr.DateTime.Interval.to_string ~U[2020-01-01 00:00:00.0Z], ~U[2020-12-31 10:00:00.0Z],
...> format: :medium, date_format: :long, time_format: :short
{:ok, "January 1, 2020, 12:00 AM – December 31, 2020, 10:00 AM"}
iex> MyApp.Cldr.DateTime.Interval.to_string ~U[2020-01-01 00:00:00.0Z], ~U[2020-01-01 10:00:00.0Z],
...> format: :medium, date_format: :long, time_format: :short
{:ok, "January 1, 2020, 12:00 AM – 10:00 AM"}
The same options are also added to Cldr.DateTime.to_string/2
as well (and required to support intervals anyway):
iex> MyApp.Cldr.DateTime.to_string ~U[2020-01-01 00:00:00.0Z], format: :medium, date_format: :long, time_format: :short
{:ok, "January 1, 2020, 12:00 AM"}
iex> MyApp.Cldr.DateTime.to_string ~U[2020-01-01 00:00:00.0Z], format: :medium, date_format: :short, time_format: :long
{:ok, "1/1/20, 12:00:00 AM UTC"}
iex> MyApp.Cldr.DateTime.to_string ~U[2020-01-01 00:00:00.0Z], format: :short, date_format: :long, time_format: :short
{:ok, "January 1, 2020, 12:00 AM"}
Thanks @kipcole9 . Love this! I'll try this out on the weekend.
I might be pushing my luck here (and stretching my memory), but is there a :thin
option from time (e.g., 12AM) in the CLDR standard? Wondering if I can get a DateTime range even smaller e.g., January 1, 2020, 12AM – 10AM . Either way, this looks really good.
but is there a :thin option from time (e.g., 12AM)
Nope, :short
is as short as it gets. I could, I think, make it so you can specify the format string directly for the date and time parts. So you could use time_fomat: "Ha"
but that then makes you less locale aware.
that then makes you less locale aware
That's fair. It would obviate the point of using a cldr library in the first place. Thanks for getting back to this. I'll let you know how I go
I've added some tests so when you're happy its operating as expected I'll publish to hex.
Thanks, Kip. I was sick last weekend, but I should be able to have a crack at it this week.
Jarrod, sorry to hear that. No rush at all - I'm the one that has slowed down resolution.
I wanted to publish a release that fixes compiler warnings on Elixir 1.16 so I've published ex_cldr_dates_times version 2.16.0 with the following changelog entry:
Fix formatting time intervals when the to
time is not greater than the from
time. This allows time intervals that cross midnight to be formatted correctly. Thanks to @larshei for the report. Closes #42.
Fix compiler warnings on Elixir 1.16.
:date_format
and :time_format
to Cldr.DateTime.Interval.to_string/2
and Cldr.DateTime.to_string/2
. These options allow separate formatting of the date and time parts of a datetime, including those that are part of an interval. Thanks to @jmoldrich for the report (and patience). Closes #33.I'll close this issue as completed but of course please reopen if it's not operating as you expected. Thanks again for y our support - and especially patience.
Thanks Kip. Really appreciate this. I'll probably have a chance to try it out tomorrow
Hi Kip,
Thanks again for this amazing library. It's been so useful to me.
I've been using the DateTime Intervals and I'm wishing there was a way to have
:medium
formatted dates and:short
formatted times. For e.g.,Apr 22, 2022, 2:00:00 AM – 3:00:00 AM
->Apr 22, 2022, 2:00 AM – 3:00 AM
... or ideally this ...
Apr 22, 2022, 2:00:00 AM – 3:00:00 AM
->Apr 22, 2022, 2 AM – 3 AM
I feel like remove the redundant parts of the time makes it more legible, but a shorter date is less legible and less friendly, and doesn't generalise if I don't have the exact locale (e.g., 'en-GB' vs 'en-US'). So ideally I want:
Cldr.DateTime.Interval.to_string(start, finish, locale: locale, date_format: :medium, time_format: :short)
Looking at
cldr_dates_times/blob/master/lib/cldr/interval/date_time.ex
it appears that formats could be percolated down to the output functions, but the format forDateTime
s are coarse at the moment, and the 'common date time formats' don't feature formats with both date and time. So I'm thinking the DateTimeto_string
method could be changed to handle mixed formats.In the meantime I've hacked together something that works for me. It might be useful for someone else, so here it is:
Perhaps there's already a better way to do this with what's already there? Maybe it doesn't make sense to have this kind of complexity within the library? But I'd be curious to know what you think.
Cheers,
Jarrod