Java: DateTimeFormatter fail to parse time string when seconds and milliseconds are all 0s?

老子叫甜甜 提交于 2019-12-01 07:18:46

问题


Basically, I am using the following code to parse string as LocalDateTime, which works fine most of the time.

DateTimeFormatter dtformatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");

However, I encounter cases where the seconds and millseconds are 00000 and this is when the parser fails and print a LocalDateTime 2018-03-01T09:16 instead of 2018-03-01T09:16:00.000.

System.out.println(LocalDateTime.parse("20180301091600000",dtformatter));

(Note that in my code, I have to parse string as LocalDateTime, do some comparison and then at the end, print LocalDateTime to csv)

How can I fix it to make it print 2018-03-01T09:16:00.000 instead of 2018-03-01T09:16 ?

FYI, I am using jdk10.


回答1:


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



回答2:


tl;dr

where the seconds and millseconds are 00000 and this is when the parser fails

No, the parser succeeds. Your issue is with generating a String, not parsing.

The default DateTimeFormatter suppresses zero values in seconds and fractional second, as documented.

Feature, not a bug

Your problem is not in the parsing, but in the generating of a string after parsing. Keep in mind that the textual representation of a date-time object is distinct and separate from the object. In other words, a date-time object does not have a “format”.

[String] --> parse --> [LocalDateTime] --> toString --> [String]

The documentation for LocalDateTime::toString clearly says that the shortest possible formatting variation will be used when encountering zero values in the least-significant parts. To quote:

The output will be one of the following ISO-8601 formats:

uuuu-MM-dd'T'HH:mm

uuuu-MM-dd'T'HH:mm:ss

uuuu-MM-dd'T'HH:mm:ss.SSS

uuuu-MM-dd'T'HH:mm:ss.SSSSSS

uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS

The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.

Examples

Regarding two examples shown in the accepted Answer by YCF_L…

20180301091600001 result is 2018-03-01T09:16:00.001

In that example, the least-significant part (millisecond) has a non-zero value, so it is represented in the result.

2018030100000000 result is 2018-03-01T00:00

In that example, the least significant parts of hour, minute, second, milliseconds, microseconds, and nanoseconds are all zero. So their display is suppressed, except for hours and minutes as the documentation promises that year-minute is always displayed.

So both of your examples work as documented; feature, not a bug.

Solution

The solution is to not use the default formatter provided in the toString method. Instead, use another formatter. For example, use the same custom formatter you defined for parsing.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS" );
LocalDateTime ldt = LocalDateTime.parse( "20180301091600000" , f );

String outputDefault = ldt.toString();
String outputCustom = ldt.format( f );

Dump to console.

System.out.println( "outputDefault: " + outputDefault );
System.out.println( "outputCustom: " + outputCustom );

outputDefault: 2018-03-01T09:16

outputCustom: 20180301091600000

The Question asks:

How can I fix it to make it print 2018-03-01T09:16:00.000 instead of 2018-03-01T09:16 ?

Specify a custom formatter instead of the default formatter.

DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS") ; 
String output = ldt.format( f ) ;

But keep in mind your generated String will suppress display of any microseconds or nanoseconds in the LocalDateTime object.



来源:https://stackoverflow.com/questions/49967139/java-datetimeformatter-fail-to-parse-time-string-when-seconds-and-milliseconds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!