java.time.format.DateTimeParseException 无法解析,从Java 8迁移到Java 11

huangapple go评论69阅读模式
英文:

java.time.format.DateTimeParseException could not be parsed migrating from Java 8 to Java 11

问题

这在Java 8中有效:

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM", DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]"));

但在Java 11中,我得到以下错误:

java.time.format.DateTimeParseException: Text '4/11/17 00:00 AM' could not be parsed, unparsed text found at index 14
	at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2049)
	at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)

有谁能帮我理解为什么会这样?我已经检查了文档,没有看到DateTimeFormatter类有任何明显的变化。

https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html

英文:

This works in Java 8

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM", DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]"));

But in Java 11 I get

java.time.format.DateTimeParseException: Text '4/11/17 00:00 AM' could not be parsed, unparsed text found at index 14
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2049)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1948)

Can anyone help me understand why this is? I've checked the docs and don't see any obvious change to the DateTimeFormatter class.

https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html

答案1

得分: 12

什么都没变。您正在提交一个“默认平台”代码样式错误。这是一种反模式,您在使用错误的方法并破坏代码,但几乎不可能通过单元测试找到错误;当大量现金和声誉处于风险时,您的代码最终将在生产时爆炸。 “幸运的是”,今天您通过切换JDK发现了这个错误,并且因为不同的区域配置,幸运地找到了这个错误。

我建议您对这些糟糕的方法和我一样产生厌恶感:)这些方法是那些假设某个参数是“您的平台默认值”的方法,其中3个常见的罪魁祸首依次是:

  • 字符集编码
  • 区域设置
  • 时区

ofPattern(String) 就是其中之一;它假设“平台默认区域设置”,显然,在您的JDK8安装中,它是英语或类似的东西,在您的JDK11安装中则不是。将 AM 解析为 a 字段的值是与区域设置相关的;显然,AM 是一种英式用法,在荷兰语或法语中没有任何意义!

要解决这个问题,有两件事情要做:

  1. 如果您的IDE具有将方法标记为“您确实不应该调用此方法”的功能,您应该强烈考虑将所有这些方法添加到该列表中,然后如果您确实希望使用平台默认值,您应该明确使用 Charset.defaultCharset() 等方法,以明确您真正需要它。

  2. 通过在模式后面插入 , Locale.ENGLISH 来修复您的代码,一切都会恢复正常。

示例:

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM",
  DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]",
  Locale.forLanguageTag("NL")));

在JDK8上失败的程度与在JDK11上一样。

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM",
  DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]",
  Locale.ENGLISH));

在JDK8和JDK11上都可以工作。

注:一些非英语区域(例如.GERMANY.ITALY.FRANCE)实际上确实可以正确解析 AM,但正如上面所示,荷兰语(荷兰)是一个无法正常工作的示例。

英文:

Nothing changed. You're committing a 'default platform' code style error. This is an anti-pattern where you use a broken method and break your code, but the bug is almost impossible to find with unit tests; your code will end up blowing up at production time when lots of cash and reputation is on the line. "Fortunately", you found this bug today by switching JDKs and getting lucky that the locale configurations are somehow different between your JDK installations.

I suggest you grow just as much of a dislike to these bad methods as I do java.time.format.DateTimeParseException 无法解析,从Java 8迁移到Java 11 These methods are ones that presume some parameter to be 'whatever your platform has as a default for this value', and the 3 common culprits are, in order:

  • Charset encoding
  • Locale
  • Timezone

ofPattern(String) is one such method; it presumes 'the platform default locale', and evidently, on your JDK8 install, it's english or something similar and on your JDK11 install it is not. Parsing AM as value for an a field is locale dependent; obviously, AM is an englishism, it wouldn't make any sense in dutch or french!

There are 2 things to do to fix this problem:

  1. If your IDE has features to mark a method as 'you really should never call this', you should strongly consider adding all of these methods to the list, and if you then want platform default, that you explicitly use things like Charset.defaultCharset() instead, to make clear you really want that.

  2. Fix your code by shoving a , Locale.ENGLISH after your pattern and all will be right as rain again.

An example:

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM",
  DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]",
  Locale.forLanguageTag("NL")));

will fail on JDK8 just as much as it does on JDK11.

LocalDateTime ldt = LocalDateTime.parse("4/11/17 00:00 AM",
  DateTimeFormatter.ofPattern("d/M/yy hh:mm[ ][a]",
  Locale.ENGLISH));

works on JDK8 and JDK11 too.

NB: A bunch of non-english locales such as .GERMANY and .ITALY and .FRANCE actually do somehow parse AM correctly, but as shown above, dutch (The Netherlands) is an example where that won't work.

huangapple
  • 本文由 发表于 2020年9月2日 19:19:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/63704418.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定