找出解决方法,通过月份名称的拼写来绕过 Java.time 错误

问题描述 投票:0回答:1

我最近发现了一个 java.time 错误。复制它非常容易;

我在 MacOS X 和 Centos Stream 9 上的 JDK 17.0.10 和 JDK 21.0.4 上进行了测试

代码为:

public class JakartaDateTime {

public static void main(String[] args) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy");
    LocalDateTime now = LocalDateTime.now();
    System.out.println(formatter.format(now));
}

此代码将打印一个字符串

Fri Sept 06 23:10:23 2024

当然,这不是我预想的,预想的结果应该是:

Fri Sep 06 23:10:23 2024

我已将其作为错误报告给 java bug 报告和 Oracle bug 数据库 ID:9077542。我确信它不会很快得到修复。所以我必须找到一种解决方法来避免它。

我正在尝试使用 gson 将收入 json 映射到我们的 java 类,json 对象键/值对为:

{"date":"Fri Sep 06 23:10:23 2024"}

所以,我必须编写一个反序列化器来将该字符串解析为 java.time.LocalDateTime。我做了这样的事情:

public class EuDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
    String dateTimeStr =jsonElement.getAsString();
    if(!ThssUtils.isValidString(dateTimeStr)){
        return null;
    }else {
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy"));
    }
  }
}

但是这个解串器仅适用于 9 月以外的其他月份。

抛出错误:

java.time.format.DateTimeParseException: Text 'Fri Sep  6 15:42:12 2024' could not be parsed at index 4

这意味着解串器无法识别上面的字符串。

有人有这样的经验来找到解决方法来避免以前的 java.time 错误吗?

请多指教!

java parsing exception time
1个回答
4
投票

tl;博士

不是错误。指定

Locale

DateTimeFormatter.ofPattern( … ).withLocale( locale )

功能,而不是错误

虽然您忽略了确切提及您认为是“错误”的内容,但我认为您指的是 9 月与

t
中缺失的
Sep

本地化

日期时间格式中的拼写、缩写和标点符号取决于

Locale
Locale
对象中包含的人类语言和文化规范控制着本地化的过程。

指定
Locale

这里我们指定美国英语🇺🇸。我们得到

Sep

LocalDateTime ldt = LocalDateTime.of( 2024 , Month.SEPTEMBER , 6 , 23 , 10 , 23 , 0 );
System.out.println( "ldt = " + ldt );

Locale locale = Locale.of( "en" , "US" );
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "EEE MMM dd HH:mm:ss yyyy" ).withLocale( locale );
String output = formatter.format( ldt );

System.out.println( "output = " + output );

ldt = 2024-09-06T23:10:23

输出 = 2024 年 9 月 6 日星期五 23:10:23

在澳大利亚将该区域设置更改为英语🇦🇺。我们得到

Sept

Locale locale = Locale.of( "en" , "AU" );

ldt = 2024-09-06T23:10:23

输出 = 2024 年 9 月 6 日星期五 23:10:23

在加拿大将该区域设置更改为法语🇨🇦。我们得到带标点符号的小写

sept.

Locale locale = Locale.of( "fr" , "CA" );

输出 = 文。九月2024 年 06 23:10:23

撤回您的错误错误报告

提示:在怀疑与 Java 捆绑的库之前,请始终怀疑您自己的代码,或者您自己的误解。是的,错误可能会潜入 Java 实现的代码库中。但像您在这里指控的错误很少见。用于大多数 Java 实现的OpenJDK 代码库是有史以来经过最彻底检查和测试的代码之一(除了军事和航空航天等专业之外)。

避免
LocalDateTime.now

顺便说一句,您的代码调用

LocalDateTime.now
。我无法想象这样做是明智之举的场景。那堂课不能代表一个时刻。

A

LocalDateTime
对象表示带有一天中的时间的日期,但缺少与 UTC 或时区的偏移量的上下文。如果没有上下文,我们无法知道您指的是澳大利亚图文巴晚上 11 点、法国图卢兹晚上 11 点还是美国俄亥俄州托莱多晚上 11 点——三个截然不同的时刻,相隔几个小时。

要捕获当前时刻,请使用跟踪时间轴上特定点的三个类之一:

  • Instant
  • OffsetDateTime
  • ZonedDateTime

第一个和第三个最常见用于商业目的,而第二个主要用于与 SQL 数据库进行交换。

Instant now = Instant.now() ;  // Capture current moment as seen "in UTC", meaning an offset from UTC of zero hours-minutes-seconds. 

通过特定时区的挂钟/日历查看同一时刻。

ZoneId z = ZoneId.of( "Australia/Brisbane" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
© www.soinside.com 2019 - 2024. All rights reserved.