Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8031085

DateTimeFormatter won't parse dates with custom format "yyyyMMddHHmmssSSS"

    Details

    • Subcomponent:
    • Resolved In Build:
      b116
    • OS:
      windows_8

      Description

      FULL PRODUCT VERSION :
      java version "1.8.0-ea"
      Java(TM) SE Runtime Environment (build 1.8.0-ea-b120)
      Java HotSpot(TM) 64-Bit Server VM (build 25.0-b62, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Windows 8.1

      A DESCRIPTION OF THE PROBLEM :
      Java 8 produces

      java.time.format.DateTimeParseException: Text '20130812214600025' could not be parsed at index 0

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      run this with java 8

      String x = "20130812214600025";
      DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
      LocalDateTime t1 = LocalDateTime.parse(x, dtf);

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      parsed successfully
      ACTUAL -
      Exception in thread "main" java.time.format.DateTimeParseException: Text '20130812214600025' could not be parsed at index 0
      at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1948)
      at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1850)
      at java.time.LocalDateTime.parse(LocalDateTime.java:484)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      String x = "20130812214600025";
      DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
      LocalDateTime t1 = LocalDateTime.parse(x, dtf);
      ---------- END SOURCE ----------

        Issue Links

          Activity

          Hide
          bpb Brian Burkhalter added a comment -
          Attached test class.
          Show
          bpb Brian Burkhalter added a comment - Attached test class.
          Hide
          rriggs Roger Riggs added a comment -
          As currently specified and implemented Fractions do not participate in the protocol for adjacent value parsing.
          The fraction digits are included in the digits available for parsing the year, month, day, etc.
          The excess digits cause the parsing of the year to terminate with an parsing error.
          Adding an explicit decimal point (".") before the fraction in both the pattern and the data allows the parse to succeed.
          Show
          rriggs Roger Riggs added a comment - As currently specified and implemented Fractions do not participate in the protocol for adjacent value parsing. The fraction digits are included in the digits available for parsing the year, month, day, etc. The excess digits cause the parsing of the year to terminate with an parsing error. Adding an explicit decimal point (".") before the fraction in both the pattern and the data allows the parse to succeed.
          Hide
          maxelsso Mathias Axelsson (Inactive) added a comment -
          Release team: Approved for deferral. We're putting this on 9 for now. You can backport it to 8u if needed.
          Show
          maxelsso Mathias Axelsson (Inactive) added a comment - Release team: Approved for deferral. We're putting this on 9 for now. You can backport it to 8u if needed.
          Hide
          rriggs Roger Riggs added a comment -
          A possible workaround is to use the pattern lettern "n", for NANO_OF_SECOND or explicitly use the DateTimeFormatBuilder to do the equivalent - appendValue(ChronoField.NANO_OF_SECOND, n).
          Show
          rriggs Roger Riggs added a comment - A possible workaround is to use the pattern lettern "n", for NANO_OF_SECOND or explicitly use the DateTimeFormatBuilder to do the equivalent - appendValue(ChronoField.NANO_OF_SECOND, n).
          Hide
          scolebourne Stephen Colebourne added a comment -
          Workaround:

          DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmss").appendValue(ChronoField.MILLI_OF_SECOND, 3).toFormatter()

          Adjacent value parsing is generally a hard problem. It is intended to handle the case where the first element is variable width (the year) and all other elements are fixed width (month, day etc). However, the "S" pattern letter is a fraction, not a value. Specifically, the fraction can be variable width - more or less than three digits are possible options. Given the general case of a variable width year and a variable width millisecond, it is not possible to determine which of the two fields was intended to be variable.

          Having said that, the implementation (and javadoc) have not ended up as I intended. The description of "fraction" in DateTimeFormatter describes actions in strict and lenient mode, but there is no way to access strict or lenient mode when using DateTimeFormatter.ofPattern(). This is a documentation bug that should be fixed by removing the discussion of strict vs lenient.

          Worse however is that the SSS pattern has therefore ended up using strict mode when lenient mode would be appropriate. As it currently stands, DateTimeFormatter.ofPattern("hhmmss.SSS") requires three digits for milliseconds, when it was originally intended to require 0 to 9 (the lenient behaviour).

          I tried changing the whole of the DateTimeFormatter.ofPattern() method to use lenient parsing, and it broke no tests (which is bad in its own way). This might be a valid fix, but only if included in JDK 8, as once people adapt to the strict parsing it will be hard to make it lenient.

          Given that the current implementation requires three digits for SSS, it is thus very surprising that adjacent value parsing does not apply.
          Show
          scolebourne Stephen Colebourne added a comment - Workaround: DateTimeFormatter dtf = new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmss").appendValue(ChronoField.MILLI_OF_SECOND, 3).toFormatter() Adjacent value parsing is generally a hard problem. It is intended to handle the case where the first element is variable width (the year) and all other elements are fixed width (month, day etc). However, the "S" pattern letter is a fraction, not a value. Specifically, the fraction can be variable width - more or less than three digits are possible options. Given the general case of a variable width year and a variable width millisecond, it is not possible to determine which of the two fields was intended to be variable. Having said that, the implementation (and javadoc) have not ended up as I intended. The description of "fraction" in DateTimeFormatter describes actions in strict and lenient mode, but there is no way to access strict or lenient mode when using DateTimeFormatter.ofPattern(). This is a documentation bug that should be fixed by removing the discussion of strict vs lenient. Worse however is that the SSS pattern has therefore ended up using strict mode when lenient mode would be appropriate. As it currently stands, DateTimeFormatter.ofPattern("hhmmss.SSS") requires three digits for milliseconds, when it was originally intended to require 0 to 9 (the lenient behaviour). I tried changing the whole of the DateTimeFormatter.ofPattern() method to use lenient parsing, and it broke no tests (which is bad in its own way). This might be a valid fix, but only if included in JDK 8, as once people adapt to the strict parsing it will be hard to make it lenient. Given that the current implementation requires three digits for SSS, it is thus very surprising that adjacent value parsing does not apply.
          Hide
          scolebourne Stephen Colebourne added a comment -
          If the appendFraction() method is called in strict mode with width == maxWidth and decimalPoint == false then the code could use adjacent parsing mode. This would not be against the spec as the spec does not mention adjacent parsing in appendFraction().

          However, implementing such a change would require a new inner class (subclass of NumberPrinterParser) in order to resolve the fraction. Given that users can just call appendValue() themselves it is not obvious that this is the right course of action wrt DTFBuilder. But if ofPattern() remains strict, then making the change described in this comment would make sense.
          Show
          scolebourne Stephen Colebourne added a comment - If the appendFraction() method is called in strict mode with width == maxWidth and decimalPoint == false then the code could use adjacent parsing mode. This would not be against the spec as the spec does not mention adjacent parsing in appendFraction(). However, implementing such a change would require a new inner class (subclass of NumberPrinterParser) in order to resolve the fraction. Given that users can just call appendValue() themselves it is not obvious that this is the right course of action wrt DTFBuilder. But if ofPattern() remains strict, then making the change described in this comment would make sense.
          Hide
          hgupdate HG Updates added a comment -
          URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/06bd77b3af21
          User: ntv
          Date: 2016-04-25 09:39:28 +0000
          Show
          hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/06bd77b3af21 User: ntv Date: 2016-04-25 09:39:28 +0000
          Hide
          hgupdate HG Updates added a comment -
          URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/06bd77b3af21
          User: lana
          Date: 2016-04-27 18:46:47 +0000
          Show
          hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/06bd77b3af21 User: lana Date: 2016-04-27 18:46:47 +0000

            People

            • Assignee:
              ntv Nadeesh Tv
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: