一尘不染

java.time是否无法解析秒的分数?

java

在Mac OS X(Mavericks)上的Java 8(b132)的第一个发行版中,使用新java.time包的此代码有效:

String input = "20191203123456"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHHmmss");
LocalDateTime localDateTime = LocalDateTime.parse( input, formatter );

渲染:

2019-12-03T12:34:56

但是,当我在DateTimeFormatter类doc中指定的几分之一秒内添加“ SS”(并输入“ 55”)时,将引发异常:

java.time.format.DateTimeParseException: Text '2011120312345655' could not be parsed at index 0

文档说严格模式是默认使用的,并且需要与输入数字相同数量的格式字符。所以我很困惑为什么这段代码失败:

String input = "2011120312345655"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSS");
LocalDateTime localDateTime = LocalDateTime.parse( input, formatter );

使用文档(“ 978”)中的示例的另一个示例(失败):

String input = "20111203123456978"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS");
LocalDateTime localDateTime = LocalDateTime.parse( input, formatter );

此示例有效,添加了一个小数点(但我在文档中没有找到这样的要求):

String input = "20111203123456.978"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHHmmss.SSS");
LocalDateTime localDateTime = LocalDateTime.parse( input, formatter );

渲染:

localDateTime: 2011-12-03T12:34:56.978

从输入字符串或格式中省略句点字符会导致失败。

失败:

String input = "20111203123456.978"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS");
LocalDateTime localDateTime = LocalDateTime.parse( input, formatter );

失败:

String input = "20111203123456978"; 
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyyMMddHHmmss.SSS");
LocalDateTime localDateTime = LocalDateTime.parse( input, formatter );

阅读 345

收藏
2020-03-20

共1个答案

一尘不染

错误-Java 9中已修复
此问题已在JDK-bug-log中报告。Stephen Colebourne提到以下解决方法:

DateTimeFormatter dtf = 
  new DateTimeFormatterBuilder()
  .appendPattern("yyyyMMddHHmmss")
  .appendValue(ChronoField.MILLI_OF_SECOND, 3)
  .toFormatter();

注意:此解决方法不能涵盖仅两个模式符号SS的用例。调整可能仅是使用其他字段,例如MICRO_OF_SECOND(SSSSSS的6倍)或NANO_OF_SECOND(SSSSSSSSS的9倍)。对于两个小数位数,请参见下面的更新。

@PeterLawrey关于模式符号“ S”的含义,请参见此文档:

分数:以秒为单位输出毫微秒的字段。毫微秒的值具有9位数字,因此,图案字母的计数为1到9。如果小于9,则毫微秒的值将被截断,仅输出最高有效位。在严格模式下解析时,解析位数必须与模式字母的数量匹配。在宽大模式下解析时,解析的位数必须至少是模式字母的数量,最多9位。

因此,我们看到S代表秒的任何分数(包括纳秒),而不仅仅是毫秒。此外,不幸的是,小数部分目前无法很好地进行相邻值解析。

编辑:

作为背景,这里有一些关于相邻值解析的说明。只要用小数点或时间部分分隔符(冒号)之类的文字来分隔字段,对要解析的文本中的字段进行解释就并不困难,因为解析器随后便知道何时停止(即何时结束字段部分)以及下一个字段开始时。因此,如果指定小数点,则JSR-310解析器可以处理文本序列。

但是,如果你有一个跨越多个字段的相邻数字序列,那么会出现一些实现上的困难。为了让解析器知道某个字段何时在文本中停止,必须事先指示解析器给定的字段由固定宽度的数字字符表示。这适用于所有appendValue(…)采用数字表示法的方法。

不幸的是,JSR-310的小数部分(appendFraction(…))也无法很好地做到这一点。如果在类的javadoc中DateTimeFormatterBuilder寻找关键字“ adjacent”,那么你会发现此功能仅由appendValue(…)-methods 实现。请注意,模式字母S的规范略有不同,但内部代表appendFraction()-method。我认为至少要等到Java 9(如JDK-bug-log或更高版本中所述),直到小数部分也可以管理相邻的值解析为止。

2020-03-20