Summary
-------
Support additional custom locale date/time formats defined in CLDR.
Problem
-------
Currently `java.time.format.DateTimeFormatter` supports 4 pre-defined format styles, for example, `FormatStyle.FULL/LONG/MEDIUM/SHORT`. Users cannot use localized formats in a more flexible manner, such as a format that contains only year and month. For example, consider getting the title string for a typical month for a calendar user interface. Currently, the typical way is to assume an explicit pattern, such as `DateTimeFormatter.ofPattern("MMM y")` which is proven to be incorrect for some locales.
Solution
--------
Provide a method analogous to `java.time.format.DateTimeFormatter#ofPattern` that takes the template based on [Skeleton patterns defined in CLDR][1]. It returns the localized formatter based on passed skeletons. Also, add supporting methods in `java.time.format.DateTimeFormatterBuilder` class that are the basis for the method in `DateTimeFormatter`.
Specification
-------------
Add the following method to `java.time.format.DateTimeFormatter` class:
/**
* Creates a locale specific formatter derived from the requested template for
* the ISO chronology. The requested template is a series of typical pattern
* symbols in canonical order from the largest date or time unit to the smallest,
* which can be expressed with the following regular expression:
* {@snippet :
* "G{0,5}" + // Era
* "y*" + // Year
* "Q{0,5}" + // Quarter
* "M{0,5}" + // Month
* "w*" + // Week of Week Based Year
* "E{0,5}" + // Day of Week
* "d{0,2}" + // Day of Month
* "B{0,5}" + // Period/AmPm of Day
* "[hHjC]{0,2}" + // Hour of Day/AmPm (refer to LDML for 'j' and 'C')
* "m{0,2}" + // Minute of Hour
* "s{0,2}" + // Second of Minute
* "[vz]{0,4}" // Zone
* }
* All pattern symbols are optional, and each pattern symbol represents a field,
* for example, 'M' represents the Month field. The number of the pattern symbol letters follows the
* same presentation, such as "number" or "text" as in the <a href="#patterns">Patterns for
* Formatting and Parsing</a> section. Other pattern symbols in the requested template are
* invalid.
* <p>
* The mapping of the requested template to the closest of the available localized formats
* is defined by the
* <a href="https://www.unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems">
* Unicode LDML specification</a>. For example, the formatter created from the requested template
* {@code yMMM} will format the date '2020-06-16' to 'Jun 2020' in the {@link Locale#US US locale}.
* <p>
* The locale is determined from the formatter. The formatter returned directly by
* this method uses the {@link Locale#getDefault() default FORMAT locale}.
* The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
* on the result of this method.
* <p>
* The returned formatter has no override zone.
* It uses {@link ResolverStyle#SMART SMART} resolver style.
*
* @param requestedTemplate the requested template, not null
* @return the formatter based on the {@code requestedTemplate} pattern, not null
* @throws IllegalArgumentException if {@code requestedTemplate} is invalid
* @see #ofPattern(String)
* @since 19
*/
public static DateTimeFormatter ofLocalizedPattern(String requestedTemplate)
Add the following methods to `java.time.format.DateTimeFormatterBuilder` class:
/**
* Appends a localized pattern to the formatter using the requested template.
* <p>
* This appends a localized section to the builder, suitable for outputting
* a date, time or date-time combination. The format of the localized
* section is lazily looked up based on three items:
* <ul>
* <li>the {@code requestedTemplate} specified to this method
* <li>the {@code Locale} of the {@code DateTimeFormatter}
* <li>the {@code Chronology} of the {@code DateTimeFormatter} unless overridden
* </ul>
* During formatting, the chronology is obtained from the temporal object
* being formatted, which may have been overridden by
* {@link DateTimeFormatter#withChronology(Chronology)}.
* <p>
* During parsing, if a chronology has already been parsed, then it is used.
* Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)}
* is used, with {@code IsoChronology} as the fallback.
* <p>
* The requested template is a series of typical pattern
* symbols in canonical order from the largest date or time unit to the smallest,
* which can be expressed with the following regular expression:
* {@snippet :
* "G{0,5}" + // Era
* "y*" + // Year
* "Q{0,5}" + // Quarter
* "M{0,5}" + // Month
* "w*" + // Week of Week Based Year
* "E{0,5}" + // Day of Week
* "d{0,2}" + // Day of Month
* "B{0,5}" + // Period/AmPm of Day
* "[hHjC]{0,2}" + // Hour of Day/AmPm (refer to LDML for 'j' and 'C')
* "m{0,2}" + // Minute of Hour
* "s{0,2}" + // Second of Minute
* "[vz]{0,4}" // Zone
* }
* All pattern symbols are optional, and each pattern symbol represents a field,
* for example, 'M' represents the Month field. The number of the pattern symbol letters follows the
* same presentation, such as "number" or "text" as in the
* <a href="./DateTimeFormatter.html#patterns">Patterns for Formatting and Parsing</a> section.
* Other pattern symbols in the requested template are invalid.
* <p>
* The mapping of the requested template to the closest of the available localized formats
* is defined by the
* <a href="https://www.unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems">
* Unicode LDML specification</a>. For example, the formatter created from the requested template
* {@code yMMM} will format the date '2020-06-16' to 'Jun 2020' in the {@link Locale#US US locale}.
*
* @param requestedTemplate the requested template to use, not null
* @return this, for chaining, not null
* @throws IllegalArgumentException if {@code requestedTemplate} is invalid
* @see #appendPattern(String)
* @since 19
*/
public DateTimeFormatterBuilder appendLocalized(String requestedTemplate)
/**
* Returns the formatting pattern for the requested template for a locale and chronology.
* The locale and chronology are used to lookup the locale specific format
* for the requested template.
* <p>
* If the locale contains the "rg" (region override)
* <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
* the formatting pattern is overridden with the one appropriate for the region.
* <p>
* Refer to {@link #appendLocalized(String)} for the detail of {@code requestedTemplate}
* argument.
*
* @param requestedTemplate the requested template, not null
* @param chrono the Chronology, non-null
* @param locale the locale, non-null
* @return the locale and Chronology specific formatting pattern
* @throws IllegalArgumentException if {@code requestedTemplate} does not match
* the regular expression syntax described in {@link #appendLocalized(String)}.
* @throws DateTimeException if a match for the localized pattern for
* {@code requestedTemplate} is not available
* @see #appendLocalized(String)
* @since 19
*/
public static String getLocalizedDateTimePattern(String requestedTemplate,
Chronology chrono, Locale locale)
[1]: https://www.unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems