java.time 是否无法解析几分之一秒? [英] Is java.time failing to parse fraction-of-second?

查看:27
本文介绍了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

但是当我为秒的分数添加SS"(和55"作为输入)时,如DateTimeFormatter class 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 );

<小时>

这个例子有效,添加了一个小数点(但我在文档中没有发现这样的要求):


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

<小时>

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


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 );

推荐答案

Bug – 在 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 次 SSSSSSSS).对于两位小数,请参阅下面我的更新.

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:

Fraction:输出纳秒字段作为秒的分数.纳秒值有九位数字,因此模式的计数字母是从 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(...) 方法.

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 中,您会发现此功能仅通过 appendValue(...)-methods 实现.请注意,模式字母 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 日的更新:

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

The following code using two fraction digits only does not work and misinterpretes the millisecond part:

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

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

剩下的解决方案是等待 Java 9(或更高版本?)或编写自己的 hack 或使用第 3 方库作为解决方案.

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:

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.

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

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

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