Java LocalDateTime.parse with millisecond precisio

2020-04-16 05:31发布

Is there a way to create a LocalDateTime pattern that will parse a date/time that has at least millisecond precision but optional microsecond precision i.e. in the following the millisecond date/time is parsed ok but the second one in microseconds fails. I thought the optional indicators in the pattern "[" "]" would allow this work:

DateTimeFormatter DATE_TIME_FORMATTER = 
    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS[SSS]");
System.out.println(LocalDateTime.parse("2019-02-14 11:04:52.784", DATE_TIME_FORMATTER));     
System.out.println(LocalDateTime.parse("2019-02-14 11:04:52.784108", DATE_TIME_FORMATTER));

1条回答
成全新的幸福
2楼-- · 2020-04-16 06:11

Hack no. 1

    String withMillis = "2019-02-14 11:04:52.784";
    String withMicros = "2019-02-14 11:04:52.784108";

    System.out.println(LocalDateTime.parse(withMillis.replace(' ', 'T')));
    System.out.println(LocalDateTime.parse(withMicros.replace(' ', 'T')));
2019-02-14T11:04:52.784
2019-02-14T11:04:52.784108

When we replace the space in the middle of your string with a T, the string conforms to ISO 8601, the standard format that LocalDateTime and the other classes of java.time parse (and also print) as their default, that is, without any explicit formatter. So this is an easy solution.

Hack no. 2

Something like what you tried can be made to work. Only you cannot split a sequence of SSSSSS with a square bracket in the middle.

static final DateTimeFormatter DATE_TIME_FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.[SSSSSS][SSS]");

And then:

    System.out.println(LocalDateTime.parse(withMillis, DATE_TIME_FORMATTER));     
    System.out.println(LocalDateTime.parse(withMicros, DATE_TIME_FORMATTER));

I specify optionally 6 decimals and then optionally 3 decimals. We need that order. If we put [SSS][SSSSSS] and try to parse 6 decimals, the formatter will first parse 3 and then throw an exception because it cannot parse the remaining 3 with SSSSSS. It’s a bit of a hack since it will also accept a decimal point with no decimals at all, and will probably issue a very confusing error message (or possibly even give an incorrect result) if we give it 9 decimals.

The good solution: use a builder

static final DateTimeFormatter DATE_TIME_FORMATTER = 
        new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE)
                .appendLiteral(' ')
                .appendPattern("HH:mm:ss")
                .appendFraction(ChronoField.NANO_OF_SECOND, 1, 9, true)
                .toFormatter();

Here I have specified a minimum of 1 and a maximum of 9 decimals after the decimal point. You can specify 3 and 6 if you prefer. It will of course accept 4 or 5 too.

Link: Wikipedia article: ISO 8601

查看更多
登录 后发表回答