Skip to content

8364752: java.time.Instant should be able to parse ISO 8601 offsets of the form HH:mm:ss #26708

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

naotoj
Copy link
Member

@naotoj naotoj commented Aug 8, 2025

Instant.parse() is expected to use the offset zone pattern +HH:mm:ss (as defined by DateTimeFormatterBuilder.appendOffsetId()), but it fails to parse hour-only offsets such as +02. This is because the actual implementation uses +HH:MM:ss as the pattern. While replacing the pattern in the implementation as with the specification would allow hour-only offsets, it would also introduce compatibility issues, i.e., printing would omit the minutes field when it is zero. So, it is preferable to update the specification to match the implementation. A CSR has also been drafted for this change.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change requires CSR request JDK-8365182 to be approved

Issues

  • JDK-8364752: java.time.Instant should be able to parse ISO 8601 offsets of the form HH:mm:ss (Bug - P3)
  • JDK-8365182: java.time.Instant should be able to parse ISO 8601 offsets of the form HH:mm:ss (CSR)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/26708/head:pull/26708
$ git checkout pull/26708

Update a local copy of the PR:
$ git checkout pull/26708
$ git pull https://git.openjdk.org/jdk.git pull/26708/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 26708

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

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/26708.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Aug 8, 2025

👋 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.

@openjdk
Copy link

openjdk bot commented Aug 8, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk
Copy link

openjdk bot commented Aug 8, 2025

@naotoj The following labels will be automatically applied to this pull request:

  • core-libs
  • i18n

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added core-libs [email protected] i18n [email protected] rfr Pull request is ready for review labels Aug 8, 2025
@naotoj naotoj changed the title 8365182: Class java.time.Instant cannot parse all ISO 8601 date formats 8364752: Class java.time.Instant cannot parse all ISO 8601 date formats Aug 8, 2025
@openjdk openjdk bot added the csr Pull request needs approved CSR before integration label Aug 8, 2025
@mlbridge
Copy link

mlbridge bot commented Aug 8, 2025

@ExE-Boss
Copy link

ExE-Boss commented Aug 9, 2025

How about using different patterns for parsing and printing instead?

@vy
Copy link
Contributor

vy commented Aug 11, 2025

Shall we accompany the changes with a set of tests that verifies java.time.Instant::parse against all all ISO 8601 date formats?

@naotoj
Copy link
Member Author

naotoj commented Aug 11, 2025

How about using different patterns for parsing and printing instead?

In fact, the current DateTimeFormatterBuilder.InstantPrinterParser already use different behavior for formatting, i.e., only print time in "Z" (no offset).

The following change:

--- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
+++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java
@@ -3887,7 +3887,7 @@ public int parse(DateTimeParseContext context, CharSequence text, int position)
                     .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
                     .appendValue(SECOND_OF_MINUTE, 2)
                     .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true)
-                    .appendOffsetId()
+                    .appendOffset("+HH:mm:ss", "Z")
                     .toFormatter().toPrinterParser(false);
             DateTimeParseContext newContext = context.copy();
             int pos = parser.parse(newContext, text, position);

will parse hour-only offset for Instant.parse() but I am not sure we would go for this, as other ISO formatters all use "MM" for minutes. @jodastephen any suggestions?

@naotoj
Copy link
Member Author

naotoj commented Aug 11, 2025

Shall we accompany the changes with a set of tests that verifies java.time.Instant::parse against all all ISO 8601 date formats?

I don't think Instant.parse() allows all permitted zone offset styles in ISO, only allowing "+HH:MM:ss" in strict mode. If the user wants to allow all of the format, they would be able to create a custom formatter in lenient mode and use the pattern "+HH" for offset parsing.

@naotoj
Copy link
Member Author

naotoj commented Aug 14, 2025

Changed the proposed fix to leniently allow all ISO 8601 offsets by using "+HH" as the pattern.

Copy link
Contributor

@vy vy left a comment

Choose a reason for hiding this comment

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

Thanks for adding the tests. In its current state, it LGTM based on my limited understanding. I'll leave the final approval to those more knowledgeable in this area.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't copyright year need a bump?

{"2017-01-01T00:00:00.000"},
{"2017-01-01T00:00:00.000+0"},
{"2017-01-01T00:00:00.000+0:"},
{"2017-01-01T00:00:00.000+02:"},
Copy link
Contributor

@vy vy Aug 15, 2025

Choose a reason for hiding this comment

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

It is nice that leniency allows 0200 (i.e., missing white space), but not 02: or 02:00: (i.e., trailing separators).

Copy link
Contributor

@jodastephen jodastephen left a comment

Choose a reason for hiding this comment

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

Looks like a good solution to the problem, thanks.


@Test(dataProvider = "valid_instants")
public void test_parse_valid(String instant) {
Instant.parse(instant);
Copy link
Contributor

Choose a reason for hiding this comment

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

The test should verify the correct time is parsed.
And include cases where the minute and second are non-zero.

@@ -3887,7 +3889,8 @@ public int parse(DateTimeParseContext context, CharSequence text, int position)
.appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true)
.appendOffsetId()
.parseLenient()
.appendOffset("+HH", "Z")
Copy link
Contributor

Choose a reason for hiding this comment

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

The "+HH" pattern is supposed to be ignoring minutes and seconds but it does not appear to. In jshell, I see:

jshell> Instant.parse("2017-01-01T00:00:00.000-02:10:12")
$8 ==> 2017-01-01T02:10:12Z

It would be more consistent with the original pattern to use "+HH:mm:ss"

Copy link
Member Author

Choose a reason for hiding this comment

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

IIUC, "ignoring minutes and seconds" refers to formatting, i.e, "-02:10:12" only prints "-02" Parsing offsets in lenient mode always parses minute/seconds.

Copy link
Contributor

Choose a reason for hiding this comment

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

True, but you have to read further into the appendOffset prose to know that the minutes and sections can be present. Using the full pattern would convey more quickly the full syntax being parsed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Using the full pattern means the colons may not be optional. The appendOffset spec reads:

If the specified pattern is "+HH", the presence of colons is determined by whether the character after the hour digits is a colon or not.

Among the supported patterns, only "+HH" (and I believe "+H" too) take the colons optional in lenient mode, i.e, both "+02:00" and "+0200" are allowed, which suits the ISO 8601 offset format.

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, thanks for the explanation of the parsing format.

@naotoj naotoj changed the title 8364752: Class java.time.Instant cannot parse all ISO 8601 date formats 8364752: java.time.Instant should be able to parse ISO 8601 offsets of the form HH:mm:ss Aug 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-libs [email protected] csr Pull request needs approved CSR before integration i18n [email protected] rfr Pull request is ready for review
Development

Successfully merging this pull request may close these issues.

5 participants