Skip to content

Commit 7c28315

Browse files
committed
Improve format option consistency checking
1 parent 818d490 commit 7c28315

File tree

2 files changed

+89
-26
lines changed

2 files changed

+89
-26
lines changed

lib/cldr/date_time.ex

+60-26
Original file line numberDiff line numberDiff line change
@@ -196,18 +196,14 @@ defmodule Cldr.DateTime do
196196

197197
def to_string(%{} = datetime, backend, options)
198198
when is_atom(backend) and is_list(options) and has_date_and_time(datetime) do
199-
options = normalize_options(datetime, backend, options)
200199
format_backend = Module.concat(backend, DateTime.Formatter)
201-
format = options.format
202200

203-
calendar = Map.get(datetime, :calendar, Cldr.Calendar.Gregorian)
204-
datetime = Map.put_new(datetime, :calendar, calendar)
205-
206-
with {:ok, locale} <- Cldr.validate_locale(options.locale, backend),
207-
{:ok, cldr_calendar} <- Cldr.DateTime.type_from_calendar(calendar),
201+
with {:ok, datetime, options} <- normalize_options(datetime, backend, options),
202+
{:ok, locale} <- Cldr.validate_locale(options.locale, backend),
203+
{:ok, cldr_calendar} <- Cldr.DateTime.type_from_calendar(datetime.calendar),
208204
{:ok, _} <- Cldr.Number.validate_number_system(locale, options.number_system, backend),
209205
{:ok, format, options} <-
210-
find_format(datetime, format, locale, cldr_calendar, backend, options),
206+
find_format(datetime, options.format, locale, cldr_calendar, backend, options),
211207
{:ok, format} <- apply_unicode_or_ascii_preference(format, options.prefer),
212208
{:ok, format_string} <- resolve_plural_format(format, datetime, backend, options) do
213209
format_backend.format(datetime, format_string, locale, options)
@@ -325,23 +321,32 @@ defmodule Cldr.DateTime do
325321
{locale, _backend} = Cldr.locale_and_backend_from(nil, backend)
326322
number_system = Cldr.Number.System.number_system_from_locale(locale, backend)
327323

324+
calendar = Map.get(datetime, :calendar, Cldr.Calendar.Gregorian)
325+
datetime = Map.put_new(datetime, :calendar, calendar)
326+
328327
{format, date_format, time_format} =
329328
formats_from_options(datetime, nil, nil, nil, @default_format_type)
330329

331-
%{
332-
locale: locale,
333-
number_system: number_system,
334-
format: format,
335-
date_format: date_format,
336-
time_format: time_format,
337-
style: @default_style,
338-
prefer: @default_prefer
339-
}
330+
options =
331+
%{
332+
locale: locale,
333+
number_system: number_system,
334+
format: format,
335+
date_format: date_format,
336+
time_format: time_format,
337+
style: @default_style,
338+
prefer: @default_prefer
339+
}
340+
341+
{:ok, datetime, options}
340342
end
341343

342344
defp normalize_options(datetime, backend, options) do
343345
{locale, backend} = Cldr.locale_and_backend_from(options[:locale], backend)
344346

347+
calendar = Map.get(datetime, :calendar, Cldr.Calendar.Gregorian)
348+
datetime = Map.put_new(datetime, :calendar, calendar)
349+
345350
style = options[:style] || @default_style
346351
prefer = options[:prefer] || @default_prefer
347352

@@ -355,15 +360,44 @@ defmodule Cldr.DateTime do
355360
{format, date_format, time_format} =
356361
formats_from_options(datetime, format, date_format, time_format, @default_format_type)
357362

358-
options
359-
|> Map.new()
360-
|> Map.put(:locale, locale)
361-
|> Map.put(:format, format)
362-
|> Map.put(:date_format, date_format)
363-
|> Map.put(:time_format, time_format)
364-
|> Map.put(:style, style)
365-
|> Map.put(:prefer, prefer)
366-
|> Map.put(:number_system, number_system)
363+
with :ok <- validate_formats_consistent(format, date_format, time_format) do
364+
options =
365+
options
366+
|> Map.new()
367+
|> Map.put(:locale, locale)
368+
|> Map.put(:format, format)
369+
|> Map.put(:date_format, date_format)
370+
|> Map.put(:time_format, time_format)
371+
|> Map.put(:style, style)
372+
|> Map.put(:prefer, prefer)
373+
|> Map.put(:number_system, number_system)
374+
375+
{:ok, datetime, options}
376+
end
377+
end
378+
379+
defp validate_formats_consistent(format, nil = _date_format, nil = _time_format)
380+
when is_atom(format) or is_binary(format) do
381+
:ok
382+
end
383+
384+
defp validate_formats_consistent(nil, date_format, time_format)
385+
when not is_nil(date_format) and not is_nil(time_format) do
386+
:ok
387+
end
388+
389+
defp validate_formats_consistent(format, date_format, time_format)
390+
when format in @format_types and date_format in @format_types and time_format in @format_types do
391+
:ok
392+
end
393+
394+
defp validate_formats_consistent(format, date_format, time_format)
395+
when is_atom(format) or is_binary(format) do
396+
{:error, {Cldr.DateTime.InvalidFormat,
397+
":date_format and :time_format cannot be specified if :format is also specified as " <>
398+
"a format id or a format string. Found [time_format: #{inspect time_format}, " <>
399+
"date_format: #{inspect date_format}]"
400+
}}
367401
end
368402

369403
# Returns the CLDR calendar type for a calendar

test/cldr_dates_times_test.exs

+29
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,33 @@ defmodule Cldr.DatesTimes.Test do
9393
{:error,
9494
{Cldr.DateTime.UnresolvedFormat, "No available format resolved for :hme"}}
9595
end
96+
97+
test "Datetime formatting with standard formats" do
98+
datetime = ~U[2024-07-07 21:36:00.440105Z]
99+
100+
assert {:ok, "Jul 7, 2024, 9:36:00 PM"} =
101+
Cldr.DateTime.to_string(datetime)
102+
103+
assert {:ok, "7/7/24, 9:36:00 PM GMT"} =
104+
Cldr.DateTime.to_string(datetime, date_format: :short, time_format: :full)
105+
106+
assert {:ok, "7/7/24, 9:36:00 PM GMT"} =
107+
Cldr.DateTime.to_string(datetime, format: :medium, date_format: :short, time_format: :full)
108+
end
109+
110+
test "Datetime format option consistency" do
111+
datetime = ~U[2024-07-07 21:36:00.440105Z]
112+
113+
assert Cldr.DateTime.to_string(datetime, format: "yyy", date_format: :short, time_format: :medium)
114+
{:error,
115+
{Cldr.DateTime.InvalidFormat,
116+
":date_format and :time_format cannot be specified if :format is also specified as a " <>
117+
"format id or a format string. Found [time_format: :medium, date_format: :short]"}}
118+
119+
assert Cldr.DateTime.to_string(datetime, format: :yMd, date_format: :short, time_format: :medium)
120+
{:error,
121+
{Cldr.DateTime.InvalidFormat,
122+
":date_format and :time_format cannot be specified if :format is also specified as a " <>
123+
"format id or a format string. Found [time_format: :medium, date_format: :short]"}}
124+
end
96125
end

0 commit comments

Comments
 (0)