具有德语语言环境的SimpleDateFormat – Java 8与Java 10
作者:互联网
我在遗留应用程序中有代码和测试用例,可以总结如下:
@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.
我知道日期格式是changed with JDK 9(JEP 252).但是,我认为这是一个破坏向后兼容性的破坏性变化.摘录:
In JDK 9, the Unicode Consortium’s Common Locale Data Repository (CLDR) data is enabled as the default locale data, so that you can use standard locale data without any further action.
In JDK 8, although CLDR locale data is bundled with the JRE, it isn’t enabled by default.
Code that uses locale-sensitive services such as date, time, and number formatting may produce different results with the CLDR locale data.
添加一个.对于星期几(Mo.)补偿这一点,测试将通过.但是,这不是旧数据的真正解决方案(以序列化形式,如XML).
检查此stackoverflow post,似乎该行为是德国语言环境的故意,可以通过使用COMPAT模式指定java.locale.providers来缓解.但是,我不喜欢依赖于某些系统属性值的想法有两个原因:
>更改JDK的下一个版本.
>在不同的环境中被遗忘.
我的问题是:
>如何保持遗留代码与此特定日期模式的向后兼容性,而无需重新编写/修改现有序列化数据或添加/更改系统属性(如java.locale.providers),这些属性可能在不同环境中被遗忘(应用程序服务器) ,独立罐子,……)?
解决方法:
我不是说这是一个很好的解决方案,但似乎是一种方法.
Map<Long, String> dayOfWeekTexts = Map.of(1L, "Mo", 2L, "Di",
3L, "Mi", 4L, "Do", 5L, "Fr", 6L, "Sa", 7L, "So");
Map<Long, String> monthTexts = Map.ofEntries(Map.entry(1L, "Jan"),
Map.entry(2L, "Feb"), Map.entry(3L, "Mär"), Map.entry(4L, "Apr"),
Map.entry(5L, "Mai"), Map.entry(6L, "Jun"), Map.entry(7L, "Jul"),
Map.entry(8L, "Aug"), Map.entry(9L, "Sep"), Map.entry(10L, "Okt"),
Map.entry(11L, "Nov"), Map.entry(12L, "Dez"));
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.DAY_OF_WEEK, dayOfWeekTexts)
.appendLiteral(' ')
.appendText(ChronoField.MONTH_OF_YEAR, monthTexts)
.appendPattern(" dd HH:mm:ss z Z yyyy")
.toFormatter(Locale.GERMANY);
String toParse = "Mo Aug 18 11:25:26 MESZ +0200 2014";
OffsetDateTime odt = OffsetDateTime.parse(toParse, formatter);
System.out.println(odt);
ZonedDateTime zdt = ZonedDateTime.parse(toParse, formatter);
System.out.println(zdt);
在我的Oracle JDK 10.0.1上运行的输出:
2014-08-18T11:25:26+02:00
2014-08-18T11:25:26+02:00[Europe/Berlin]
然后,再也没有好的解决方案.
java.time是现代Java日期和时间API,允许我们指定用于格式化和解析的字段的文本.因此,我将其用于星期和月份,指定与旧COMPAT或JRE语言环境数据一起使用的没有点的缩写.我使用Java 9 Map.of和Map.ofEntries来构建我们需要的地图.如果这也适用于Java 8,你必须找到一些其他方法来填充这两个地图,我相信你这样做.
如果你确实需要一个老式的java.util.Date(可能在遗留代码库中),请像这样转换:
Date date = Date.from(odt.toInstant());
System.out.println("As legacy Date: " + date);
在我的时区输出(欧洲/哥本哈根,可能与您的大致一致):
As legacy Date: Mon Aug 18 11:25:26 CEST 2014
对策略的建议
我想如果那是我,我会考虑这样做:
>等等.在Java中设置相关的系统属性:System.setProperty(“java.locale.providers”,“COMPAT,CLDR”);所以在任何环境中都不会忘记. COMPAT语言环境数据自1.0以来一直存在(我相信,至少接近),因此很多代码依赖于它(不仅仅是你的).在Java 9中,名称已从JRE更改为COMPAT.对我而言,这可能听起来像是一个保持数据相当长一段时间的计划.根据the early access documentation,它仍将在Java 11(下一个“长期支持”Java版本)中提供,并且没有弃用警告等.如果在将来的Java版本中将其删除,您可能很快就会发现在升级之前可以处理问题.
>使用上面的解决方案.
>使用Basil Bourque链接的the locale service provider interface.毫无疑问,如果将来某个未知时间删除COMPAT数据,这是一个很好的解决方案.您甚至可以将COMPAT语言环境数据复制到您自己的文件中,这样他们就无法将它们从您身边带走,只有在您执行此操作之前,才能检查是否存在版权问题.我之前提到最好的解决方案的原因是你说你不满意必须在程序可能运行的每个可能环境中设置系统属性.据我所知,通过语言环境服务提供程序接口使用您自己的语言环境数据仍然需要您设置相同的系统属性(仅限于不同的值).
标签:java-10,java,java-8,simpledateformat,java-9 来源: https://codeday.me/bug/20190930/1836710.html