gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 20:58:39 27 4
gpt4 key购买 nike

随着 Java 8 (b132) 在 Mac OS X (Mavericks) 上的第一个版本,使用新 java.time package 的代码可以工作:

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

渲染:

2011-12-03T12:34:56

但是,当我按照 DateTimeFormatter class 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 );

最佳答案

错误 - 在 Java 9 中已修复

此问题已在 JDK-bug-log 中报告。 Stephen Colebourne 提到以下解决方案作为变通方法:

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

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

@PeterLawrey 关于模式符号“S”的含义见this documentation:

Fraction: Outputs the nano-of-second field as a fraction-of-second.The nano-of-second value has nine digits, thus the count of patternletters is from 1 to 9. If it is less than 9, then the nano-of-secondvalue is truncated, with only the most significant digits beingoutput. When parsing in strict mode, the number of parsed digits mustmatch the count of pattern letters. When parsing in lenient mode, thenumber of parsed digits must be at least the count of pattern letters,up to 9 digits.

所以我们看到 S 代表秒的任意分数(包括纳秒),而不仅仅是毫秒。此外,不幸的是,小数部分目前在相邻值解析中表现不佳。

编辑:

作为背景,这里有一些关于相邻值解析的评论。只要字段由小数点或时间部分分隔符(冒号)之类的文字分隔,要解析的文本中的字段的解释并不困难,因为解析器然后很容易知道何时停止,即字段部分何时结束并且当下一个字段开始时。因此,如果您指定小数点,JSR-310 解析器可以处理文本序列。

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

不幸的是,JSR-310 并没有很好地处理小数部分(appendFraction(...))。如果您在 DateTimeFormatterBuilder 类的 javadoc 中查找关键字“adjacent”,您会发现此功能仅由 appendValue(...) 方法实现。请注意,模式字母 S 的规范略有不同,但在内部委托(delegate)给 appendFraction() 方法。我假设我们至少要等到 Java 9(如 JDK-bug-log 中所报告的,或更高版本???),直到分数部分也可以管理相邻的值解析。


2015 年 11 月 25 日更新:

以下仅使用两个小数位的代码不起作用并误解了毫秒部分:

    DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 2)
.toFormatter();
String input = "2011120312345655";
LocalDateTime ldt = LocalDateTime.parse(input, dtf);
System.out.println(ldt); // 2011-12-03T12:34:56.055

解决方法

String input = "2011120312345655"; 
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSS");
Date d = sdf.parse(input);
System.out.println(d.toInstant()); // 2011-12-03T12:34:56.055Z

不起作用,因为 SimpleDateFormat 也以错误的方式解释分数,类似于现代示例(参见输出,55 ms 而不是 550 ms)。

剩下的解决方案要么在 Java 9(或更高版本?)之前等待很长时间,要么编写自己的 hack 或使用 3rd 方库作为解决方案。

基于肮脏黑客的解决方案:

String input = "2011120312345655"; 
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
int len = input.length();
LocalDateTime ldt = LocalDateTime.parse(input.substring(0, len - 2), dtf);
int millis = Integer.parseInt(input.substring(len - 2)) * 10;
ldt = ldt.plus(millis, ChronoUnit.MILLIS);
System.out.println(ldt); // 2011-12-03T12:34:56.550

使用 Joda-Time 的解决方案:

String input = "2011120312345655"; 
DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyyMMddHHmmssSS");
System.out.println(dtf.parseLocalDateTime(input)); // 2011-12-03T12:34:56.550

使用我的库 Time4J 的解决方案:

String input = "2011120312345655"; 
ChronoFormatter<PlainTimestamp> f =
ChronoFormatter.ofTimestampPattern("yyyyMMddHHmmssSS", PatternType.CLDR, Locale.ROOT);
System.out.println(f.parse(input)); // 2011-12-03T12:34:56.550

2016 年 4 月 29 日更新:

正如人们通过上面提到的 JDK 问题看到的那样,它现在被标记为已解决 - 对于 Java 9

关于java - java.time 是否无法解析秒的分数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22588051/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com