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

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

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

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

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

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

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

这是Java 8中的一个错误:bugs.openjdk.java.net/browse/JDK-8031085。但是它应该在Java 9中修复,因此在Java 10中看到它是令人惊讶的。

解析器似乎很好,否则它除了解析错误外根本不会打印任何内容。您的问题似乎是打印LocalDateTime的默认格式。您还应该格式化打印件。

您的代码在我的Java 9上执行得很好。

@ OleV.V。我正在使用Java 10返回2018-03-01T09:16

我在Java 9和10 @YCF_L上都得到了相同的结果。这也是我所期望的结果。顺便说一句,mynameisJeFF,是什么让您认为自己有问题? 2018-03-01T09:16:00.000是ISO 8601,但是2018-03-01T09:16也是如此,因此任何接受前者的API都希望它也接受后者。尝试看看您是否还不错。

@ OleV.V。为什么20180301091600001返回2018-03-01T09:16:00.001但20180301091600000返回2018-03-01T00:00为什么不返回2018-03-01T00:00:00.000

@YCF_L为了简洁起见,我想(我没有设计)。在2018-03-01T00:00中,可以理解秒和秒的小数均为0,因此不需要打印它们。我认为Basil Bourque的答案可以解释。顺便说一句,为了进行比较,如果要打印LocalDateTime对象的完整精度,则需要2018-03-01T00:00:00.000000000。

@YCF_L还请记住,LocalDateTime对象不知道(不记得)它是从哪个字符串中解析的。它只保存一个日期和一天中的某个时间(精度为纳秒)。

@ OleV.V。好的,我同意这不是错误,但是OP希望获取2018-03-01T09:16:00.000而不是2018-03-01T09:16,所以我认为我的解决方案正确吗?

TL;博士

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

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

如记录所示,默认的DateTimeFormatter以秒为单位,零秒抑制零值。

功能,而非错误

您的问题不在于解析,而在于解析后生成字符串。请记住,日期时间对象的文本表示形式是不同的,并且与对象分离。换句话说,日期时间对象没有"格式"。

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

LocalDateTime::toString的文档明确指出,在最低有效部分遇到零值时,将使用最短的格式变化。报价:

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.

例子

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

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

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

2018030100000000 result is 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 );

转储到控制台。

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

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

outputDefault: 2018-03-01T09:16

outputCustom: 20180301091600000

问题问:

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

指定自定义格式器,而不是默认格式器。

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

String output = ldt.format( f ) ;

但是请记住,生成的String将禁止显示LocalDateTime对象中的任何微秒或纳秒。

@Basil Bourque,您好,但是OP想要产生2018-03-01T09:16:00:000,所以我认为您的解决方案不是OP想要的吗?

@YCF_L所需的输出是不相关的-Question的问题(请参阅标题)认为解析器解析失败,并且省略了数据。但是不,Question中的代码隐式调用toString,它使用格式化程序,该格式化程序以秒和小数秒为单位抑制零值。因此,问题的前提是错误的。至于所需的格式,这是附带问题,已经以数百种(甚至数千种)现有问题和答案进行了处理。我想我可以显示这样的格式代码,但这不重要,您已经做得很好。

您是英雄@Basil阅读报告,我刚刚收到报告bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8202144它与您在回答中已经提到的相同:)

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

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

----------------^                       -----------------^^^^^^

另外另一个测试:

2018030100000000         result is      2018-03-01T00:00

--------^^^-----                        -----------^^^^^^^^^^^

似乎解析器忽略为零的秒和毫秒,为什么?

罗勒·布尔克(Basil Bourque)的回答是为什么?的完整解释。

这是一个快速解决方案,您可以在其中使用另一个格式程序,如下所示:

var result = LocalDateTime.parse("20180301091600000", dtformatter)

.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS"));

产量

2018-03-01T09:16:00:000

非常感谢。我知道这一定是一个错误。

@mynameisJEFF没问题,我报告它打开jdk,所以我们可以等到他们确定问题出在哪

@YCF_L您可以链接到您的错误报告吗?

@BasilBourque我报告了这个问题,但是我没有任何链接,我认为需要花费一些时间来分析并确定是否是错误。

@BasilBourque您可以再报告一次吗?

@YCF_L不,我不认为这是一个错误。请参阅此页面上的我的答案。

换句话说,@YCF_L您的"临时解决方案"是正确的,并且不仅仅是临时解决方案,而是解决方案。

谢谢@ OleV.V。那么我将删除那说是错误的部分