具有德语语言环境的SimpleDateFormat - Java 8与Java 10+ [英] SimpleDateFormat with German Locale - Java 8 vs Java 10+

查看:80
本文介绍了具有德语语言环境的SimpleDateFormat - Java 8与Java 10+的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在旧版应用程序中有代码和测试用例,可以总结如下:

I have code and a test-case in a legacy application, which can be summarized as follows:

@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

This test passes in Java 8 and below. However with Java 10 upwards this leads to a java.text.ParseException: Unparseable date: "Mo Aug 18 11:25:26 MESZ +0200 2014".

记录
de_DE 外,还有例外情况为区域设置抛出
de_CH de_AT de_LU

For the record: Besides de_DE, the exception is also thrown for the locales de_CH, de_AT, de_LU.

我知道日期格式是随JDK 9改变 JEP 252 )。但是,我认为这是破坏向后兼容性的破坏性变化。摘录:

I am aware of the fact, that Date formatting was changed with JDK 9 (JEP 252). However, I consider this to be a disruptive change breaking backwards compatibility. Excerpted:


在JDK 9中,Unicode Consortium的公共区域设置数据存储库(CLDR)数据被启用为默认区域设置数据,以便您可以使用标准语言环境数据而无需任何进一步操作。

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.

在JDK 8中,尽管CLDR语言环境数据与JRE捆绑在一起,但默认情况下不会启用它。

In JDK 8, although CLDR locale data is bundled with the JRE, it isn’t enabled by default.

使用区域设置敏感服务(如日期,时间和数字格式)的代码可能会产生与CLDR区域设置数据不同的结果。

Code that uses locale-sensitive services such as date, time, and number formatting may produce different results with the CLDR locale data.

为星期几添加 Mo。)补偿这一点,测试将通过。但是,这不是旧数据的真正解决方案(以XML等序列化形式)。

Adding a . for the day of the week (Mo.) compensates for this and test would pass. However, this is not a real solution for old data (in serialized form such as XML).

检查此 stackoverflow post ,似乎该行为是故意为德国语言环境而且可以是通过使用 COMPAT 模式指定 java.locale.providers 来缓解此问题。但是,我不喜欢依赖于某些系统属性值的想法有两个原因,因为它可能:

Checking this stackoverflow post, it seems that the behaviour is intentional for the German locale and can be mitigated by specifying java.locale.providers with COMPAT mode. However, I do not like the idea to rely on some system property value for two reasons as it might:


  1. 在下一个版本中更改JDK。

  2. 在不同的环境中被遗忘。

我的问题是:


  • 如何在不重写/修改现有序列化数据的情况下,保持遗留代码与此特定日期模式的向后兼容性或添加/更改系统属性(如 java.locale.providers ),这可能会在不同环境(应用程序服务器,独立jar,......)中被遗忘?

  • How can I maintain backwards compatibility of legacy code with this particular date pattern, without re-writing / modifying existing serialized data or adding / changing system properties (like java.locale.providers), which may be forgotten in different environments (application servers, standalone jars, ...) ?

推荐答案

我不是说这是一个很好的解决方案,但似乎是一种方法。

I don’t say it’s a nice solution, but it seems to be a way through.

    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上运行的输出:

Output running on my Oracle JDK 10.0.1:

2014-08-18T11:25:26+02:00
2014-08-18T11:25:26+02:00[Europe/Berlin]

然后,再也没有好的解决方案。

Then again, no nice solution may exist.

java.time ,现代Java日期和时间API,允许我们指定用于格式化和解析的字段的文本。因此,我将其用于星期和月份,指定与旧COMPAT或JRE语言环境数据一起使用的没有点的缩写。我使用Java 9 Map.of Map.ofEntries 来构建我们需要的地图。如果这也适用于Java 8,你必须找到一些其他的方法来填充这两张地图,我相信你这样做。

java.time, the modern Java date and time API, allows us to specify texts to use for fields for both formatting and parsing. So I exploit that for both day of week and for month, specifying the abbreviations without dot that were used with the old COMPAT or JRE locale data. I have used the Java 9 Map.of and Map.ofEntries for building the maps we need. If this is to work in Java 8 too, you must find some other way to populate the two maps, I trust you to do that.

如果你确实需要一个旧的-fashioned java.util.Date (可能在遗留代码库中),转换如下:

If you do need an old-fashioned java.util.Date (likely in a legacy code base), convert like this:

    Date date = Date.from(odt.toInstant());
    System.out.println("As legacy Date: " + date);

我所在时区的输出(欧洲/哥本哈根,可能与您的大致一致):

Output in my time zone (Europe/Copenhagen, probably roughly agrees with yours):

As legacy Date: Mon Aug 18 11:25:26 CEST 2014



对策略的建议



我想如果那是我,我会考虑这样做:

Suggestion for a strategy

I am thinking that if that were me, I’d consider proceeding this way:


  1. 等待。在Java中设置相关的系统属性: System.setProperty(java.locale.providers,COMPAT,CLDR); 所以不会忘记任何环境。 COMPAT语言环境数据自1.0以来一直存在(我相信,至少接近),因此很多代码依赖于它(不仅仅是你的)。在Java 9中,名称从JRE更改为COMPAT。对我而言,这可能听起来像是一个保持数据相当长一段时间的计划。根据早期访问文档它仍将在Java 11(下一个长期支持Java版本)中提供,并且没有弃用警告等。如果在未来的Java版本中将其删除,您可能很快就会发现可以在升级之前处理问题。

  2. 使用上面的解决方案

  3. 使用语言环境服务提供者界面 。毫无疑问,如果将来某个未知时间删除COMPAT数据,这是一个很好的解决方案。您甚至可以将COMPAT语言环境数据复制到您自己的文件中,这样他们就无法将它们从您那里拿走,只有在您这样做之前才检查是否存在版权问题。我之前提到最好的解决方案的原因是你说你不满意必须在程序可能运行的每个可能环境中设置系统属性。据我所知,通过语言环境服务提供程序接口使用您自己的语言环境数据仍然需要您设置相同的系统属性(仅限于不同的值)。

  1. Wait. Set the relevant system property from within Java: System.setProperty("java.locale.providers", "COMPAT,CLDR"); so it won’t be forgot in any environment. The COMPAT locale data have been around since 1.0 (I believe, at least close), so a lot of code out there depends on it (not only yours). The name was changed from JRE to COMPAT in Java 9. To me this may sound like a plan to keep the data around for quite a while still. According to the early access documentation it will still be available in Java 11 (the next "long term support" Java version) and with no deprecation warning or the like. And should it be removed in some future Java version, you will probably be able to find out soon enough that you can deal with the problem before upgrading.
  2. Use my solution above.
  3. Use the locale service provider interface that Basil Bourque linked to. There is no doubt that this is the nice solution in case the COMPAT data should be removed some unknown time in the future. You may even be able to copy the COMPAT locale data into your own files so they can’t take them away from you, only check if there are copyright issues before you do so. The reason why I mention the nice solution last is you said you aren’t happy with having to set a system property in every possible environment where your program may run. As far as I can tell, using your own locale data through the locale service provider interface will still require you to set the same system property (only to a different value).

这篇关于具有德语语言环境的SimpleDateFormat - Java 8与Java 10+的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆