Is java.time failing to parse fraction-of-second?
Bug – Fixed in Java 9
This issue was already reported in JDK-bug-log. Stephen Colebourne mentions as work-around following solution:
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter();
Note: This workaround does not cover your use-case of only two pattern symbols SS. An adjustment might only be to use other fields like MICRO_OF_SECOND (6 times SSSSSS) or NANO_OF_SECOND (9 times SSSSSSSSS). For two fraction digits see my update below.
@PeterLawrey About the meaning of pattern symbol "S" see this documentation:
Fraction: Outputs the nano-of-second field as a fraction-of-second.
The nano-of-second value has nine digits, thus the count of pattern
letters is from 1 to 9. If it is less than 9, then the nano-of-second
value is truncated, with only the most significant digits being
output. When parsing in strict mode, the number of parsed digits must
match the count of pattern letters. When parsing in lenient mode, the
number of parsed digits must be at least the count of pattern letters,
up to 9 digits.
So we see that S stands for any fraction of second (including nanosecond), not just milliseconds. Furthermore, the fractional part does at the moment not take well in adjacent value parsing, unfortunately.
EDIT:
As background here some remarks about adjacent value parsing. As long as fields are separated by literals like a decimal point or time part separators (colon), the interpretation of fields in a text to be parsed is not difficult because the parser then knows easily when to stop i.e. when the field part is ended and when the next field starts. Therefore the JSR-310 parser can process the text sequence if you specify a decimal point.
But if you have a sequence of adjacent digits spanning over multiple fields then some implementation difficulties arise. In order to let the parser know when a field stops in text it is necessary to instruct the parser in advance that a given field is represented by a fixed-width of digit chars. This works with all appendValue(...)
-methods which assume numerical representations.
Unfortunately JSR-310 has not managed well to do this also with the fractional part (appendFraction(...)
). If you look for the keyword "adjacent" in the javadoc of class DateTimeFormatterBuilder
then you find that this feature is ONLY realized by appendValue(...)
-methods. Note that the spec for pattern letter S is slightly different but internally delegates to appendFraction()
-method. I assume we will at least have to waint until Java 9 (as reported in JDK-bug-log, or later???) until fraction parts can manage adjacent value parsing as well.
Update from 2015-11-25:
The following code using two fraction digits only does not work and misinterpretes the millisecond part:
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 2)
.toFormatter();
String input = "2011120312345655";
LocalDateTime ldt = LocalDateTime.parse(input, dtf);
System.out.println(ldt); // 2011-12-03T12:34:56.055
The workaround
String input = "2011120312345655";
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSS");
Date d = sdf.parse(input);
System.out.println(d.toInstant()); // 2011-12-03T12:34:56.055Z
does not work because SimpleDateFormat
interpretes the fraction in a wrong way, too, similar to the modern example (see output, 55 ms instead of 550 ms).
What is left as solution is either waiting an undertermined long time until Java 9 (or later?) or writing your own hack or using 3rd-party libraries as solution.
Solution based on a dirty hack:
String input = "2011120312345655";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
int len = input.length();
LocalDateTime ldt = LocalDateTime.parse(input.substring(0, len - 2), dtf);
int millis = Integer.parseInt(input.substring(len - 2)) * 10;
ldt = ldt.plus(millis, ChronoUnit.MILLIS);
System.out.println(ldt); // 2011-12-03T12:34:56.550
Solution using Joda-Time:
String input = "2011120312345655";
DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyyMMddHHmmssSS");
System.out.println(dtf.parseLocalDateTime(input)); // 2011-12-03T12:34:56.550
Solution using my library Time4J:
String input = "2011120312345655";
ChronoFormatter<PlainTimestamp> f =
ChronoFormatter.ofTimestampPattern("yyyyMMddHHmmssSS", PatternType.CLDR, Locale.ROOT);
System.out.println(f.parse(input)); // 2011-12-03T12:34:56.550
Update from 2016-04-29:
As people can see via the JDK-issue mentioned above, it is now marked as resolved - for Java 9.
JSR-310 - parsing seconds fraction with variable length
This solves the problem:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
.toFormatter();
System.out.println(LocalDateTime.parse("2015-05-07 13:20:22.276052", formatter));
System.out.println(LocalDateTime.parse("2015-05-07 13:20:22.276", formatter));
System.out.println(LocalDateTime.parse("2015-05-07 13:20:22", formatter));
// output
2015-05-07T13:20:22.276052
2015-05-07T13:20:22.276
2015-05-07T13:20:22
The answer by JiriS is incorrect, as it uses appendValue
whereas the correct way is to use DateTimeFormatterBuilder.appendFraction
(which also handles the decimal point). The difference can be seen in the second system out, where appendValue
incorrectly parses "2015-05-07T13:20:22.000276".
When parsing, LocalDateTime.parse(str, formatter)
is a neater approach than using the formatter directly in most cases.
When using the builder, take advantage of appendPattern()
and optionalStart()
to keep things neat.
DateTimeFormatter not able to parse String to LocalDateTime
You need to use the DateTimeFormatBuilder:
DateTimeFormatter formatter =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter();
Related post: Is java.time failing to parse fraction-of-second?
Java: DateTimeFormatter fail to parse time string when seconds and milliseconds are all 0s?
I'm not sure why it's not work, it seems it is a bug because when I use :
20180301091600001 result is 2018-03-01T09:16:00.001
----------------^ -----------------^^^^^^
Also another test :
2018030100000000 result is 2018-03-01T00:00
--------^^^----- -----------^^^^^^^^^^^
It seems that the parser ignore the seconds and millisecond when it is zero, why?
The full explanation why?, is in the answer of Basil Bourque.
Solution
Here is a quick fix where you can use another formatter like this :
var result = LocalDateTime.parse("20180301091600000", dtformatter)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS"));
Output
2018-03-01T09:16:00:000
Java 8 DateTimeFormatter parsing for optional fractional seconds of varying significance
Oh cool, another 15 minutes of troubleshooting yielded this:
private static final DateTimeFormatter FORMATTER =
new DateTimeFormatterBuilder().appendPattern(BASE_PATTERN) // .parseLenient()
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).toFormatter();
edit parseLenient()
is optional.
Java datetime parse exception: text cannot be parsed
This is because Java failed to parse the fraction of a second part. There is a bug in the jdk thats not fixed until Java 9. Probably that's why it fails when you move the program from one to another computer, because they used different Java runtime. You can update the runtime on your other computer to Java 9.
Or use the following code.
Locale locale = new Locale("en", "US");
DateTimeFormatter formatter =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter();
LocalTime time = LocalTime.parse("20190502050634678",formatter);
Solution is borrowed from here Is java.time failing to parse fraction-of-second? .
Related Topics
Different Between Parseint() and Valueof() in Java
Differencebetween Compare() and Compareto()
Why Doesn't Mockito Mock Static Methods
Convert a Byte Array to Integer in Java and Vice Versa
How Are Integers Internally Represented at a Bit Level in Java
Uninitialized Variables and Members in Java
How to Load Rsa Private Key from File
How to Interrupt a Serversocket Accept() Method
Should I Keep My Project Files Under Version Control
Setting the Maximum Size of a Jdialog
Java Function for Arrays Like PHP's Join()
Junit: How to Simulate System.In Testing
Java 32-Bit VS 64-Bit Compatibility
Why Does Priorityqueue.Tostring Return the Wrong Element Order