我有一段代码和一个测试用例,它们都在一个遗留应用程序中,可以总结如下:
@Test
public void testParseDate() throws ParseException {
String toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014";
String pattern = "EEE MMM dd HH:mm:ss z Z yyyy";
DateFormat dateFormatter = new SimpleDateFormat(pattern, Locale.GERMANY);
Date date = dateFormatter.parse(toParse);
//skipped assumptions
}
这个测试在Java 8及以下版本中通过。但是在Java 10及以上版本中,会导致一个java.text.ParseException: Unparseable date: "Mo Aug 18 11:25:26 MESZ +0200 2014"
的错误。
记录一下:
除了de_DE
,异常也会被抛出到其他地区设置为
de_CH
,de_AT
,de_LU
。
我知道日期格式化在JDK 9中进行了更改(JEP 252)。然而,我认为这是一项破坏向后兼容性的颠覆性变化。摘自:
在JDK 9中,默认启用Unicode Consortium的Common Locale Data Repository(CLDR)数据,因此您可以使用标准语言环境数据而无需采取进一步的操作。
在JDK 8中,虽然将CLDR语言环境数据捆绑在JRE中,但默认情况下不启用。
使用语言环境敏感服务(如日期、时间和数字格式化)的代码可能会产生与CLDR语言环境数据不同的结果。
在日期中添加星期几的缩写Mo.
可以弥补这一点,从而使测试通过。然而,这对于旧数据(以序列化形式如XML)并不是一个真正的解决方案。
根据这个stackoverflow帖子,似乎这种行为是故意的德语区域设置,可以通过指定java.locale.providers
的COMPAT
模式来减轻。然而,我不喜欢依赖某些系统属性值的想法,因为它可能:
- 在JDK的下一个版本中更改。
- 在不同的环境中被遗忘。
我的问题是:
- 如何在不重新编写/修改现有序列化数据或添加/更改系统属性(如
java.locale.providers
)的情况下,保持遗留代码与这个特定日期格式的向后兼容性,这可能会在不同的环境(应用程序服务器、独立的jar等)中被遗忘?
System.setProperty("java.locale.providers", "COMPAT,CLDR");
。这将防止在任何环境中遗忘它。当然,这仍不能保证适用于Java 11及以后的版本。您可能需要考虑一个将所有旧日期时间数据转换为ISO 8601(这似乎相当具有未来性)的项目: - Ole V.V.EE MMM dd HH:mm:ss z Z yyyy
不起作用。它会导致java.text.ParseException: Unparseable date: "Mo Aug 18 11:25:26 MESZ +0200 2014"
。 - rzo1java.locale.providers
与COMPAT
或java.util.spi.LocaleServiceProvider
API? - Basil Bourquejava.locale.providers
属性。根据 Javadocs 所述: "本地化敏感服务的搜索顺序可以通过使用 "java.locale.providers
" 系统属性进行配置。该系统属性声明了用户首选的按逗号分隔的查找本地化敏感服务的顺序。它只在 Java 运行时启动时读取,因此稍后对System.setProperty()
的调用不会影响顺序。" - Joep Weijers