我最近发现了一个 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 错误吗?
请多指教!
不是错误。指定
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 ) ;