Java 8 DateTimeFormatter 解析具有不同意义的可选小数秒

问题描述 投票:0回答:3

我的MCVE(作为TestNG单元测试):

public class MyDateTimeFormatterTest {

    private static final String BASE_PATTERN = "yyyy/MM/dd HH:mm:ss";
    private static final DateTimeFormatter FORMATTER =
            DateTimeFormatter.ofPattern(BASE_PATTERN + "[.SSSSSSSSS]");
    private static final LocalDateTime TEST_INPUT =
            LocalDateTime.of(2015, 5, 4, 12, 34, 56, 123456789);

    @DataProvider(name = "test-cases")
    public Iterator<Object[]> getTestCases() {
        return Arrays.asList(testFor("", ChronoUnit.SECONDS),
                testFor(".SSS", ChronoUnit.MILLIS),
                testFor(".SSSSSS", ChronoUnit.MICROS),
                testFor(".SSSSSSSSS", ChronoUnit.NANOS)).iterator();
    }

    @Test(dataProvider = "test-cases")
    public void testWithDefaultResolution(String input, LocalDateTime output) {
        assertThat(FORMATTER.parse(input, LocalDateTime::from), equalTo(output));
    }

    private Object[] testFor(String patternSuffix, TemporalUnit truncatedTo) {
        return new Object[] { DateTimeFormatter.ofPattern(BASE_PATTERN + patternSuffix)
                .format(TEST_INPUT), TEST_INPUT.truncatedTo(truncatedTo) };
    }
}

我正在尝试使用

String 来测试日期时间 DateTimeFormatter
 的解析,以及具有不同意义的可选小数秒
。 Javadoc 的相关部分如下:

Fraction:将纳秒场输出为秒分数。纳秒值有 9 位,因此模式字母的计数为 1 到 9。如果小于 9,则纳秒值被截断,仅输出最高有效位。

基于我有限的理解,我使用

[...]

 将小数秒标记为可选,并且由于我对不同的意义感兴趣,我认为我应该坚持 
SSSSSSSSS

但是,单元测试在解析

毫秒和微秒时失败,即第二种和第三种情况。将 ResolverStyle 更改为

LENIENT
 在这里没有帮助,因为它在解析阶段失败,而不是在解析阶段失败。
我可以知道我应该考虑哪些方法来解决我的问题吗?我应该使用

DateTimeFormatterBuilder

 来选择指定每个小数位(9 次),还是有一种“更智能”的方式来处理我的模式?

编辑

我最终找到了自己的答案...仍然会将此问题保留一天未答复,看看是否还有其他方法。

java java-time datetime-parsing
3个回答
48
投票

private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder().appendPattern(BASE_PATTERN) // .parseLenient() .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).toFormatter();

编辑

parseLenient()

可选


3
投票

你的答案

绝对是解决这个问题的优雅方法。但是,您首先尝试的也接近解决方案。您只需在指定可选模式时指定小数部分的剩余数量即可。

演示

import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Locale; import java.util.stream.Stream; public class Main { public static void main(String[] args) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss[.[SSSSSSSSS][SSSSSSSS][SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]]", Locale.ENGLISH); // Test Stream.of( "2015-05-04 12:34:56.123456789", "2015-05-04 12:34:56.123456", "2015-05-04 12:34:56.123", "2015-05-04 12:34:56" ).forEach(s -> System.out.println(LocalDateTime.parse(s, formatter))); } }

输出

2015-05-04T12:34:56.123456789 2015-05-04T12:34:56.123456 2015-05-04T12:34:56.123 2015-05-04T12:34:56

Trail:日期时间了解有关现代日期时间 API 的更多信息。


0
投票

final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.*][.SSS][.SS][.S]X");

例如
2023-10-25T10:22:28.280Z
2023-10-25T10:22:28.28Z
2023-10-25T10:22:28.2Z
2023-10-25T10:22:28Z

© www.soinside.com 2019 - 2024. All rights reserved.