Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8176706: Additional Date-Time Formats #7340

Closed
wants to merge 33 commits into from
Closed

Conversation

naotoj
Copy link
Member

@naotoj naotoj commented Feb 3, 2022

Following the prior discussion [1], here is the PR for the subject enhancement. CSR has also been updated according to the suggestion.

[1] https://mail.openjdk.java.net/pipermail/core-libs-dev/2022-January/085175.html


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed
  • Change requires a CSR request to be approved

Issues

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/7340/head:pull/7340
$ git checkout pull/7340

Update a local copy of the PR:
$ git checkout pull/7340
$ git pull https://git.openjdk.java.net/jdk pull/7340/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 7340

View PR using the GUI difftool:
$ git pr show -t 7340

Using diff file

Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/7340.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Feb 3, 2022

👋 Welcome back naoto! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@naotoj naotoj changed the title Skeleton 8176706: Additional Date-Time Formats Feb 3, 2022
@openjdk openjdk bot added core-libs core-libs-dev@openjdk.org i18n i18n-dev@openjdk.org csr Pull request needs approved CSR before integration labels Feb 3, 2022
@naotoj naotoj marked this pull request as ready for review February 4, 2022 00:05
@openjdk openjdk bot added the rfr Pull request is ready for review label Feb 4, 2022
@mlbridge
Copy link

mlbridge bot commented Feb 4, 2022

Webrevs

@@ -5015,10 +5148,16 @@ public int parse(DateTimeParseContext context, CharSequence text, int position)
* @throws IllegalArgumentException if the formatter cannot be found
*/
private DateTimeFormatter formatter(Locale locale, Chronology chrono) {
String key = chrono.getId() + '|' + locale.toString() + '|' + dateStyle + timeStyle;
var dtStyle = dateStyle !=null || timeStyle != null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switch to using requestedTemplate == null or != null as the discriminator.

validateTemplate();
}

private LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle, String requestedTemplate) {
this.dateStyle = dateStyle;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop this constructor; it opens up the possibility of ambiguity between the modes.
Keep only the two constructors with disjoint checking and initialization.

String pattern = (dtStyle ?
getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale) :
getLocalizedDateTimePattern(requestedTemplate, chrono, locale));

formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale);
DateTimeFormatter old = FORMATTER_CACHE.putIfAbsent(key, formatter);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.computeIfAbsent(key, () -> {....}) might be a bit cleaner/clearer here and avoid the race a few lines of code below. (a slight improvement in old code).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Changed to computeIfAbsent().

// validity check
var matcher = VALID_SKELETON_PATTERN.matcher(skeleton);
if (!matcher.matches()) {
throw new IllegalArgumentException("Requested template is invalid: " + requestedTemplate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The substitutions are not going to be visible in the exception message.
That might make it harder to identify and fix the cause of the exception. Perhaps the message can make it clear that the matching was done after substitutions and show the 'skeleton'.

*/
public static String getLocalizedDateTimePattern(String requestedTemplate,
Chronology chrono, Locale locale) {
Objects.requireNonNull(locale, "requestedTemplate");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo, "locale" should have been requestedTemplate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

public String getJavaTimeDateTimePattern(String requestedTemplate, String calType, Locale locale) {
LocaleProviderAdapter lpa = LocaleProviderAdapter.getResourceBundleBased();
// CLDR's 'u'/'U' are not supported in the JDK. Replace them with 'y' instead
final var modifiedSkeleton = requestedTemplate.replaceAll("[uU]", "y");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to me requestedTemplate needs to be validated when it gets passed to getLocalizedDateTimePattern, similar as to appendLocalized

Copy link
Member Author

@naotoj naotoj Feb 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a left over which should be removed. In fact, CLDR specific pattern symbols should not be accepted as the requested template. Removed the substitutions. As to the validation, it will be performed in the following LocaleResources.getLocalizedPattern() method.

@@ -104,6 +108,10 @@
"narrow.Eras"
};

// DateFormatItem prefix
final static String DATEFORMATITEM_KEY_PREFIX = "DateFormatItem.";
final static String DATEFORMATITEM_INPUT_REGIONS_PREFIX = "DateFormatItemInputRegions.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The canonical order of modifiers is "static final".

* }
* All pattern symbols are optional, and each pattern symbol represents the field it is in,
* e.g., '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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would reword as:
* 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

* {@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 will use the {@link Locale#getDefault() default FORMAT locale}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Editorial suggestion:

@@ -227,6 +227,41 @@ public static String getLocalizedDateTimePattern(FormatStyle dateStyle, FormatSt
CalendarDataUtility.findRegionOverride(locale));
}

/**
* Gets the formatting pattern for the requested template for a locale and chronology.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Returns" is more conventional (than "Gets; though it is consistent within the file)

* @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} is invalid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meaning "Invalid" should be clearly defined; repeating or refering to the template regex.

* <ul>
* <li>the {@code requestedTemplate} specified to this method
* <li>the {@code Locale} of the {@code DateTimeFormatter}
* <li>the {@code Chronology}, selecting the best available
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps "best available" should be well defined, or just drop "best".
or ...
"of the {@code DateTimeFormatter} unless overridden"

* "[vz]{0,4}" // Zone
* }
* All pattern symbols are optional, and each pattern symbol represents the field it is in,
* e.g., 'M' represents the Month field. The number of the pattern symbol letters follows the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto above:
* All pattern symbols are optional, and each pattern symbol represents the field,
* for example, 'M' represents the Month field. The number of the pattern symbol letters follows the

return formatter;
var useRequestedTemplate = requestedTemplate != null;
String key = chrono.getId() + '|' + locale.toString() + '|' +
(useRequestedTemplate ? requestedTemplate : Objects.toString(dateStyle) + timeStyle);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The boolean useRequestedTemplate isn't necessary, replace with requestedTemplate != null.

@@ -58,4 +59,23 @@ protected JavaTimeDateTimePatternProvider() {
* @since 9
*/
public abstract String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale);

/**
* Gets the formatting pattern for the requested template, calendarType, and locale.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Returns" is more conventional.

@@ -63,10 +66,22 @@ public boolean isSupportedLocale(Locale locale) {
@Override
public String getJavaTimeDateTimePattern(int timeStyle, int dateStyle, String calType, Locale locale) {
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale);
String pattern = lr.getJavaTimeDateTimePattern(
return lr.getJavaTimeDateTimePattern(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fold the parameters onto a single line.

*/
private String resolveInputSkeleton(String type) {
var regionToSkeletonMap = inputSkeletons.get(type);
return regionToSkeletonMap.getOrDefault(locale.getLanguage() + "-" + locale.getCountry(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This structure computes all the defaults even if the value isn't needed (because the value has to be passed to the getOrDefault method. Perhaps performance isn't an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, yes. I thought this was simple enough, and as you said, not performance-critical.

@magicus
Copy link
Member

magicus commented Feb 11, 2022

/label -build

@openjdk openjdk bot removed the build build-dev@openjdk.org label Feb 11, 2022
@openjdk
Copy link

openjdk bot commented Feb 11, 2022

@magicus
The build label was successfully removed.

Copy link
Contributor

@RogerRiggs RogerRiggs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

@@ -4986,9 +5101,22 @@ private String getChronologyName(Chronology chrono, Locale locale) {
* @param timeStyle the time style to use, may be null
*/
LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the constructors be private.
The combination of package protected and the style of caller doing the validation makes me a bit nervous.
There should not be any callers outside of DateTimeFormatterBuilder.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to private so that it can only be instantiated within DateTimeFormatterBuilder. Same modifications are applied to other DateTimePrinterParser implementations.

/**
* Returns the formatting pattern for the requested template, calendarType, and locale.
* Concrete implementation of this method will retrieve
* a java.time specific pattern from selected Locale Provider.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

editorial: "from the selected Locale"...

*/
public String getJavaTimeDateTimePattern(String requestedTemplate, String calType, Locale locale) {
// default implementation throws exception
throw new DateTimeException("Formatter is not available for the requested template: " + requestedTemplate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Formatting pattern is not available"...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified, as well as other minor corrections in the javadoc.

@openjdk openjdk bot removed the csr Pull request needs approved CSR before integration label Feb 16, 2022
@openjdk
Copy link

openjdk bot commented Feb 16, 2022

@naotoj This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8176706: Additional Date-Time Formats

Reviewed-by: joehw, rriggs

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 123 new commits pushed to the master branch:

  • 0af356b: 8278173: [vectorapi] Add x64 intrinsics for unsigned (zero extended) casts
  • a24498b: 8281771: Crash in java_lang_invoke_MethodType::print_signature
  • 1aff44b: 8279949: JavaThread::_free_handle_block leaks native memory
  • 394ce5f: 8280825: Modules that "provide" ToolProvider should document the name that can be used
  • 745f7e7: 8281186: runtime/cds/appcds/DumpingWithNoCoops.java fails
  • 1870465: 8281744: x86: Use short jumps in TIG::set_vtos_entry_points
  • 2fe0bf6: 8281748: runtime/logging/RedefineClasses.java failed "assert(addr != __null) failed: invariant"
  • bc61484: 8280136: Serial: Remove unnecessary use of ExpandHeap_lock
  • 2112a9d: 8246033: bin/print_config.js script uses nashorn jjs tool
  • 1c12b15: 8281741: [testbug] PrintIdealPhaseTest fails with -Xcomp
  • ... and 113 more: https://git.openjdk.java.net/jdk/compare/cda9c3011beeec8df68e78e096132e712255ce1b...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Feb 16, 2022
@naotoj
Copy link
Member Author

naotoj commented Feb 16, 2022

/integrate

@openjdk
Copy link

openjdk bot commented Feb 16, 2022

Going to push as commit 9b74c3f.
Since your change was applied there have been 130 commits pushed to the master branch:

  • 0f3d3ac: 8061729: Update java/net tests to eliminate dependency on sun.net.www.MessageHeader and some other internal APIs
  • 395bc14: 8281732: add assert for non-NULL assumption for return of unique_ctrl_out
  • d8f44aa: 8278067: Make HttpURLConnection default keep alive timeout configurable
  • 7428b37: 8281948: JFR: Parser skips too many bytes for fractional types
  • d5b4666: 8281829: runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java fails after JDK-8281467
  • fef5d74: 8281812: x86: Use short jumps in TemplateTable::condy_helper
  • a86cab8: 8236136: tests which use CompilationMode shouldn't be run w/ TieredStopAtLevel
  • 0af356b: 8278173: [vectorapi] Add x64 intrinsics for unsigned (zero extended) casts
  • a24498b: 8281771: Crash in java_lang_invoke_MethodType::print_signature
  • 1aff44b: 8279949: JavaThread::_free_handle_block leaks native memory
  • ... and 120 more: https://git.openjdk.java.net/jdk/compare/cda9c3011beeec8df68e78e096132e712255ce1b...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Feb 16, 2022
@openjdk openjdk bot closed this Feb 16, 2022
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Feb 16, 2022
@openjdk
Copy link

openjdk bot commented Feb 16, 2022

@naotoj Pushed as commit 9b74c3f.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs core-libs-dev@openjdk.org i18n i18n-dev@openjdk.org integrated Pull request has been integrated
4 participants