Java:当秒和毫秒都为 0 时,DateTimeFormatter 无法解析时间字符串?

myn*_*EFF 6 java format date java-time java-10

基本上,我使用以下代码将字符串解析为 LocalDateTime,它在大多数情况下都可以正常工作。

DateTimeFormatter dtformatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
Run Code Online (Sandbox Code Playgroud)

但是,我遇到秒和毫秒的情况00000,这是解析器失败并打印 aLocalDateTime 2018-03-01T09:16而不是2018-03-01T09:16:00.000.

System.out.println(LocalDateTime.parse("20180301091600000",dtformatter));
Run Code Online (Sandbox Code Playgroud)

(请注意,在我的代码中,我必须将字符串解析为LocalDateTime,进行一些比较,然后在最后打印LocalDateTime到 csv)

如何修复它以使其打印2018-03-01T09:16:00.000而不是打印2018-03-01T09:16

仅供参考,我正在使用 jdk10。

YCF*_*F_L 5

我不确定为什么它不起作用,这似乎是一个错误,因为当我使用时:

20180301091600001        result is      2018-03-01T09:16:00.001
----------------^                       -----------------^^^^^^
Run Code Online (Sandbox Code Playgroud)

还有另一个测试:

2018030100000000         result is      2018-03-01T00:00
--------^^^-----                        -----------^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

看起来解析器在为零时会忽略毫秒,为什么?

完整解释为什么?,是Basil Bourque的回答。


解决方案

这是一个快速修复,您可以使用另一个格式化程序,如下所示:

var result = LocalDateTime.parse("20180301091600000", dtformatter)
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS"));
Run Code Online (Sandbox Code Playgroud)

输出

2018-03-01T09:16:00:000
Run Code Online (Sandbox Code Playgroud)

  • @YCF_L 不,我不相信这是一个错误。请参阅本页我的回答。 (2认同)
  • 换句话说,@YCF_L 您的“临时解决方案”是正确的,并且不仅仅是临时解决方案,它是*解决方案。 (2认同)

Bas*_*que 5

tl;博士

其中秒和毫秒为 00000,这是解析器失败的时候

不,解析器成功了。您的问题是生成字符串,而不是解析。

如文档所示DateTimeFormatter,默认值以秒和小数秒为单位抑制零值。

功能,而不是错误

您的问题不在于解析,而在于解析生成字符串。请记住,日期时间对象的文本表示与对象不同且独立。换句话说,日期时间对象没有“格式”。

[字符串] --> parse--> [LocalDateTime] --> toString--> [字符串]

的文档LocalDateTime::toString明确指出,在最不重要的部分遇到零值时,将使用尽可能短的格式变体。报价:

输出将是以下 ISO-8601 格式之一:

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

所使用的格式将是输出完整时间值的最短格式,其中省略部分隐含为零。

例子

关于YCF_L 接受的答案中显示的两个示例......

20180301091600001 结果是 2018-03-01T09:16:00.001

在该示例中,最低有效部分(毫秒)具有非零值,因此它在结果中表示。

2018030100000000 结果是 2018-03-01T00:00

在该示例中,小时、分钟、秒、毫秒、微秒和纳秒的最低有效部分都为零。因此它们的显示被抑制,除了小时和分钟,因为文档承诺始终显示年-分钟。

所以你的两个例子都按照文档工作;功能,而不是错误。

解决方案

解决方案是不使用toString方法中提供的默认格式化程序。相反,使用另一个格式化程序。例如,使用您为解析定义的相同自定义格式化程序。

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

String outputDefault = ldt.toString();
String outputCustom = ldt.format( f );
Run Code Online (Sandbox Code Playgroud)

转储到控制台。

System.out.println( "outputDefault: " + outputDefault );
System.out.println( "outputCustom: " + outputCustom );
Run Code Online (Sandbox Code Playgroud)

输出默认值:2018-03-01T09:16

输出自定义:20180301091600000

问题问:

如何修复它以使其打印 2018-03-01T09:16:00.000 而不是 2018-03-01T09:16 ?

指定自定义格式化程序而不是默认格式化程序。

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

但请记住,您生成的 String 将抑制LocalDateTime对象中任何微秒或纳秒的显示。

  • @YCF_L 所需的输出无关紧要 - 问题的重点(见标题)是认为解析器未能解析并遗漏了数据。但是不,Question 中的代码隐式调用了 `toString`,它使用一个格式化程序来抑制秒和小数秒内的零值。所以**问题的前提是错误的**。至于所需的格式,这是一个附带问题,并且已经在数百个(如果不是数千个)现有问答中进行了处理。我想我可以展示这样的格式化代码,但这不是重点,你已经做得很好了。 (2认同)