java.time无法解析小数部分吗? [英] Is java.time failing to parse fraction-of-second?

查看:126
本文介绍了java.time无法解析小数部分吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Mac OS X(Mavericks)上首次发布Java 8(b132),此代码使用新的 java.time包有效:

With the first release of Java 8 (b132) on Mac OS X (Mavericks), this code using the new java.time package works:

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

渲染:

2011-12-03T12:34:56

但是当我为秒(和55作为输入)添加SS时,如 DateTimeFormatter类doc ,抛出异常:

But when I add "SS" for fraction-of-second (and "55" as input), as specified in the DateTimeFormatter class doc, an exception is thrown:

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

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

The doc says Strict mode is used by default and requires the same number of format characters as input digits. So I'm confused why this code fails:

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






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


Another example using example from documentation ("978") (fails):

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






此示例有效,添加小数点(但我在doc中找不到这样的要求:


This example works, adding a decimal point (but I find no such requirement in the doc):

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

呈现:

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



< hr>

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


Omitting the period character from either the input string or the format cause a fail.

失败:

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提到解决方案的解决方案:

Bug – Fixed in Java 9

This issue was already reported in JDK-bug-log. Stephen Colebourne mentions as work-around following solution:

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

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

Note: This workaround does not cover your use-case of only two pattern symbols SS. An adjustment might only be to use other fields like MICRO_OF_SECOND (6 times SSSSSS) or NANO_OF_SECOND (9 times SSSSSSSSS). For two fraction digits see my update below.

@PeterLawrey关于模式符号S的含义,请参阅此文档

@PeterLawrey About the meaning of pattern symbol "S" see this documentation:


分数:以秒为单位输出纳秒级字段。
纳秒值有九位数,因此模式
字母的数量从1到9.如果小于9,则为纳秒级
值被截断,只有最高位数是
输出。在严格模式下解析时,解析数字的数量必须是
匹配模式字母的数量。在宽松模式下解析时,
解析数字的数量必须至少为模式字母的数量,
最多9位数。

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

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

So we see that S stands for any fraction of second (including nanosecond), not just milliseconds. Furthermore, the fractional part does at the moment not take well in adjacent value parsing, unfortunately.

编辑:

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

As background here some remarks about adjacent value parsing. As long as fields are separated by literals like a decimal point or time part separators (colon), the interpretation of fields in a text to be parsed is not difficult because the parser then knows easily when to stop i.e. when the field part is ended and when the next field starts. Therefore the JSR-310 parser can process the text sequence if you specify a decimal point.

但是如果你有一系列相邻数字跨越多个字段,那么一些实现困难出现。为了让解析器知道字段何时在文本中停止,有必要事先指示解析器给定字段由固定宽度的数字字符表示。这适用于所有 appendValue(...) -methods,它们假设数字表示。

But if you have a sequence of adjacent digits spanning over multiple fields then some implementation difficulties arise. In order to let the parser know when a field stops in text it is necessary to instruct the parser in advance that a given field is represented by a fixed-width of digit chars. This works with all appendValue(...)-methods which assume numerical representations.

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

Unfortunately JSR-310 has not managed well to do this also with the fractional part (appendFraction(...)). If you look for the keyword "adjacent" in the javadoc of class DateTimeFormatterBuilder then you find that this feature is ONLY realized by appendValue(...)-methods. Note that the spec for pattern letter S is slightly different but internally delegates to appendFraction()-method. I assume we will at least have to waint until Java 9 (as reported in JDK-bug-log, or later???) until fraction parts can manage adjacent value parsing as well.

2015-11-25更新:

以下代码使用两个小数位不起作用并抛出 DateTimeParseException

The following code using two fraction digits only does not work and throws a DateTimeParseException.

DateTimeFormatter dtf = 
  new DateTimeFormatterBuilder()
  .appendPattern("yyyyMMddHHmmssSS")
  .appendValue(ChronoField.MILLI_OF_SECOND, 2)
  .toFormatter();
String input = "2011120312345655"; 
LocalDateTime.parse(input, dtf); // abort

解决方法

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毫秒而不是550毫秒)。

does not work because SimpleDateFormat interpretes the fraction in a wrong way (see output, 55 ms instead of 550 ms).

剩下的解决方案是要么等待很长时间,直到Java 9(或更高版本?),还是编写自己的hack或使用第三方库作为解决方案。

What is left as solution is either waiting an undertermined long time until Java 9 (or later?) or writing your own hack or using 3rd-party libraries as solution.

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

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

Solution using Joda-Time:

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

使用我的库的解决方案 Time4J

Solution using my library 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-04-29更新:

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

As people can see via the JDK-issue mentioned above, it is now marked as resolved - for Java 9.

这篇关于java.time无法解析小数部分吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆