From 1bd70913d39279e22bc252538650d14deca87634 Mon Sep 17 00:00:00 2001
From: Kip Cole <kipcole9@gmail.com>
Date: Fri, 27 Oct 2023 07:38:16 +0700
Subject: [PATCH] Support :date_format and :time_format options for
 Cldr.DateTime.Interval.to_string/2 and Cldr.DateTime.to_string/2. Relates to
 #33

---
 lib/cldr/backend/date_time.ex  | 48 +++++++++++++++++++++-------------
 lib/cldr/date.ex               |  6 +++--
 lib/cldr/interval/date_time.ex | 48 ++++++++++++++++++++++++++++++++++
 lib/cldr/time.ex               |  3 ++-
 4 files changed, 84 insertions(+), 21 deletions(-)

diff --git a/lib/cldr/backend/date_time.ex b/lib/cldr/backend/date_time.ex
index 86df88d..9efa8b5 100644
--- a/lib/cldr/backend/date_time.ex
+++ b/lib/cldr/backend/date_time.ex
@@ -85,20 +85,32 @@ defmodule Cldr.DateAndTime.Backend do
 
           * `format:` `:short` | `:medium` | `:long` | `:full` or a format string or
             any of the keys returned by `Cldr.DateTime.available_format_names` or a format string.
-            The default is `:medium`
+            The default is `:medium`.
+        
+          * `:date_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+            this option is used to format the date part of the date time. This option is
+            only acceptable if the `:format` option is not specified, or is specified as either
+            `:short`, `:medium`, `:long`, `:full`. If `:date_format` is not specified
+            then the date format is defined by the `:format` option.
+
+          * `:time_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+            this option is used to format the time part of the date time. This option is
+            only acceptable if the `:format` option is not specified, or is specified as either
+            `:short`, `:medium`, `:long`, `:full`. If `:time_format` is not specified
+            then the time format is defined by the `:format` option.
 
           * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
-            or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`
+            or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`.
 
           * `number_system:` a number system into which the formatted date digits should
-            be transliterated
+            be transliterated.
 
           * `era: :variant` will use a variant for the era is one is available in the locale.
             In the "en" for example, the locale `era: :variant` will return "BCE" instead of "BC".
 
           * `period: :variant` will use a variant for the time period and flexible time period if
             one is available in the locale.  For example, in the "en" locale `period: :variant` will
-            return "pm" instead of "PM"
+            return "pm" instead of "PM".
 
         ## Returns
 
@@ -140,13 +152,13 @@ defmodule Cldr.DateAndTime.Backend do
         ## Options
 
           * `format:` `:short` | `:medium` | `:long` | `:full` or a format string.
-            The default is `:medium`
+            The default is `:medium`.
 
           * `locale:` any locale returned by `Cldr.known_locale_names/1`.
             The default is `Cldr.get_locale()`.
 
           * `number_system:` a number system into which the formatted date digits
-            should be transliterated
+            should be transliterated.
 
         ## Returns
 
@@ -184,25 +196,25 @@ defmodule Cldr.DateAndTime.Backend do
 
         @doc """
         Formats a date according to a format string
-        as defined in CLDR and described in [TR35](http://unicode.org/reports/tr35/tr35-dates.html)
+        as defined in CLDR and described in [TR35](http://unicode.org/reports/tr35/tr35-dates.html).
 
         ## Arguments
 
         * `date` is a `%Date{}` struct or any map that contains the keys
-          `year`, `month`, `day` and `calendar`
+          `year`, `month`, `day` and `calendar`.
 
         * `options` is a keyword list of options for formatting.
 
         ## Options
 
           * `format:` `:short` | `:medium` | `:long` | `:full` or a format string.
-            The default is `:medium`
+            The default is `:medium`.
 
           * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
-            or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`
+            or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`.
 
           * `number_system:` a number system into which the formatted date digits should
-            be transliterated
+            be transliterated.
 
         ## Returns
 
@@ -258,20 +270,20 @@ defmodule Cldr.DateAndTime.Backend do
         ## Options
 
         * `format:` `:short` | `:medium` | `:long` | `:full` or a format string.
-           The default is `:medium`
+           The default is `:medium`.
 
         * `locale:` any locale returned by `Cldr.known_locale_names/1`.  The default is `
-          Cldr.get_locale()`
+          Cldr.get_locale()`.
 
         * `number_system:` a number system into which the formatted date digits should
-          be transliterated
+          be transliterated.
 
         * `era: :variant` will use a variant for the era is one is available in the locale.
           In the "en" locale, for example, `era: :variant` will return "BCE" instead of "BC".
 
         * `period: :variant` will use a variant for the time period and flexible time period if
           one is available in the locale.  For example, in the "en" locale `period: :variant` will
-          return "pm" instead of "PM"
+          return "pm" instead of "PM".
 
         ## Examples
 
@@ -313,20 +325,20 @@ defmodule Cldr.DateAndTime.Backend do
         ## Options
 
           * `format:` `:short` | `:medium` | `:long` | `:full` or a format string.
-             The default is `:medium`
+             The default is `:medium`.
 
           * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
             or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`
 
           * `number_system:` a number system into which the formatted date digits should
-            be transliterated
+            be transliterated.
 
           * `era: :variant` will use a variant for the era is one is available in the locale.
             In the "en" locale, for example, `era: :variant` will return "BCE" instead of "BC".
 
           * `period: :variant` will use a variant for the time period and flexible time period if
             one is available in the locale.  For example, in the "en" locale `period: :variant` will
-            return "pm" instead of "PM"
+            return "pm" instead of "PM".
 
         ## Returns
 
diff --git a/lib/cldr/date.ex b/lib/cldr/date.ex
index 6beb3f9..84c8a8e 100644
--- a/lib/cldr/date.ex
+++ b/lib/cldr/date.ex
@@ -99,11 +99,13 @@ defmodule Cldr.Date do
     options = normalize_options(backend, options)
     format_backend = Module.concat(backend, DateTime.Formatter)
     number_system = Map.get(options, :number_system)
+    format = options[:date_format] || options[:format]
+    locale = options[:locale]
 
-    with {:ok, locale} <- Cldr.validate_locale(options[:locale], backend),
+    with {:ok, locale} <- Cldr.validate_locale(locale, backend),
          {:ok, cldr_calendar} <- Cldr.DateTime.type_from_calendar(calendar),
          {:ok, _} <- Cldr.Number.validate_number_system(locale, number_system, backend),
-         {:ok, format_string} <- format_string(options[:format], locale, cldr_calendar, backend),
+         {:ok, format_string} <- format_string(format, locale, cldr_calendar, backend),
          {:ok, formatted} <- format_backend.format(date, format_string, locale, options) do
       {:ok, formatted}
     else
diff --git a/lib/cldr/interval/date_time.ex b/lib/cldr/interval/date_time.ex
index 3469e4b..1640ac6 100644
--- a/lib/cldr/interval/date_time.ex
+++ b/lib/cldr/interval/date_time.ex
@@ -57,6 +57,18 @@ defmodule Cldr.DateTime.Interval do
       specific format type or a string representing of an interval
       format. The default is `:medium`.
 
+    * `:date_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+      this option is used to format the date part of the date time. This option is
+      only acceptable if the `:format` option is not specified, or is specified as either
+      `:short`, `:medium`, `:long`, `:full`. If `:date_format` is not specified
+      then the date format is defined by the `:format` option.
+
+    * `:time_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+      this option is used to format the time part of the date time. This option is
+      only acceptable if the `:format` option is not specified, or is specified as either
+      `:short`, `:medium`, `:long`, `:full`. If `:time_format` is not specified
+      then the time format is defined by the `:format` option.
+
     * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
       or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`
 
@@ -208,6 +220,18 @@ defmodule Cldr.DateTime.Interval do
   * `:format` is one of `:short`, `:medium` or `:long` or a
     specific format type or a string representation of an interval
     format. The default is `:medium`.
+  
+  * `:date_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+    this option is used to format the date part of the date time. This option is
+    only acceptable if the `:format` option is not specified, or is specified as either
+    `:short`, `:medium`, `:long`, `:full`. If `:date_format` is not specified
+    then the date format is defined by the `:format` option.
+
+  * `:time_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+    this option is used to format the time part of the date time. This option is
+    only acceptable if the `:format` option is not specified, or is specified as either
+    `:short`, `:medium`, `:long`, `:full`. If `:time_format` is not specified
+    thenthe time format is defined by the `:format` option.
 
   * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
     or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`
@@ -398,6 +422,18 @@ defmodule Cldr.DateTime.Interval do
     * `:format` is one of `:short`, `:medium` or `:long` or a
       specific format type or a string representing of an interval
       format. The default is `:medium`.
+    
+    * `:date_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+      this option is used to format the date part of the date time. This option is
+      only acceptable if the `:format` option is not specified, or is specified as either
+      `:short`, `:medium`, `:long`, `:full`. If `:date_format` is not specified
+      then the date format is defined by the `:format` option.
+
+    * `:time_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+      this option is used to format the time part of the date time. This option is
+      only acceptable if the `:format` option is not specified, or is specified as either
+      `:short`, `:medium`, `:long`, `:full`. If `:time_format` is not specified
+      then the time format is defined by the `:format` option.
 
     * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
       or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`.
@@ -470,6 +506,18 @@ defmodule Cldr.DateTime.Interval do
   * `:format` is one of `:short`, `:medium` or `:long` or a
     specific format type or a string representation of an interval
     format. The default is `:medium`.
+  
+  * `:date_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+    this option is used to format the date part of the date time. This option is
+    only acceptable if the `:format` option is not specified, or is specified as either
+    `:short`, `:medium`, `:long`, `:full`. If `:date_format` is not specified
+    then the date format is defined by the `:format` option.
+
+  * `:time_format` is any one of `:short`, `:medium`, `:long`, `:full`. If defined,
+    this option is used to format the time part of the date time. This option is
+    only acceptable if the `:format` option is not specified, or is specified as either
+    `:short`, `:medium`, `:long`, `:full`. If `:time_format` is not specified
+    then the time format is defined by the `:format` option.
 
   * `locale` is any valid locale name returned by `Cldr.known_locale_names/0`
     or a `Cldr.LanguageTag` struct.  The default is `Cldr.get_locale/0`.
diff --git a/lib/cldr/time.ex b/lib/cldr/time.ex
index b017481..7a5a1e8 100644
--- a/lib/cldr/time.ex
+++ b/lib/cldr/time.ex
@@ -105,11 +105,12 @@ defmodule Cldr.Time do
     calendar = Map.get(time, :calendar) || Cldr.Calendar.Gregorian
     format_backend = Module.concat(backend, DateTime.Formatter)
     number_system = Map.get(options, :number_system)
+    format = options[:time_format] || options[:format]
 
     with {:ok, locale} <- Cldr.validate_locale(options[:locale], backend),
          {:ok, cldr_calendar} <- Cldr.DateTime.type_from_calendar(calendar),
          {:ok, _} <- Cldr.Number.validate_number_system(locale, number_system, backend),
-         {:ok, format_string} <- format_string(options[:format], locale, cldr_calendar, backend),
+         {:ok, format_string} <- format_string(format, locale, cldr_calendar, backend),
          {:ok, formatted} <- format_backend.format(time, format_string, locale, options) do
       {:ok, formatted}
     end