SimpleDateFormat的toPattern方法在Java 9中表现不同。

7
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, new Locale("SV", "SE"));
((SimpleDateFormat) dateFormat).toPattern();

在Java 8中,这行代码会生成"yyyy-MM-dd",而在Java 9中它会生成"y-MM-dd"。对于我们的遗留代码来说,这有一些严重的问题,是否有一种方法可以恢复其行为?

1
@ΦXocę웃Пepeúpaツ 好的,它在IntelliJ中的表达式求值是有效的,但如果不进行强制转换,它将无法编译。我已经更新了我的示例。 - Jeppz
2
可能是因为CLDR日期时间模式的原因吗?迁移指南中的重点是“如果您的应用程序成功启动,请仔细查看您的测试,并确保行为与JDK 8相同。例如,一些早期采用者已经注意到他们的日期和货币格式不同。请参阅默认使用CLDR区域设置数据。” - Naman
3
如果你需要字符串 "yyyy-MM-dd",只需使用字符串 "yyyy-MM-dd"。如果你询问一个工厂获取某个区域和样式的模式,那么你必须接受这是一个不断变化的目标。我怀疑瑞典是否愿意仅仅为了一些遗留的Java代码而固定他们的日期格式... - Holger
2
当使用Java 9时,为什么你还在使用早已过时且臭名昭著的SimpleDateFormat?我可以理解如果你现在不想从遗留代码中删除它,但对于手头的任务,请使用DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, null, IsoChronology.INSTANCE, new Locale("SV", "SE"))(虽然这并不能解决你的问题,因为它在Java 8和9中的行为也有所不同)。 - Ole V.V.
1
@Jeppz,无论您查询哪个区域设置,都不能保证其具有永不更改的属性。 - Holger
显示剩余4条评论
1个回答

8
    System.setProperty("java.locale.providers", "COMPAT,CLDR");
    DateFormat dateFormat
            = DateFormat.getDateInstance(DateFormat.SHORT, new Locale("sv", "SE"));
    System.out.println(((SimpleDateFormat) dateFormat).toPattern());

在我的jdk-9.0.4上运行,这将打印出:
"yyyy-MM-dd"
你可能想要在命令行上使用-D设置属性,这不会有任何区别。
在Java 9中,默认使用Unicode联盟的公共语言环境数据存储库(CLDR)作为语言环境数据源,而早期的Java版本则不是这样。如上所述设置系统属性可启用Java 8行为。正如nullpointer在评论中所说,您可以在此处阅读更多信息here: Use CLDR Locale Data by Default
Basil Bourque在他的评论中是正确的,通常使用小写缩写表示语言,因此您可能应该指定sv以确保不会混淆读者。

有人可能会想知道模式中是有一个 y 还是四个 y 是否有任何区别。根据我对 SimpleDateFormat 文档的理解,一个 y 将根据80-20规则解释2位数的年份:它在过去80年或未来20年内。yyyy 将把2位数的年份解释为公元1世纪的年份。假设你的年份范围在4位数范围内(1000到9999),我不认为这会成为问题。

如果这只针对瑞典语环境,那么现代版本的代码将给出相同的结果:

DateTimeFormatterBuilder.getLocalizedDateTimePattern(
        FormatStyle.SHORT, null, IsoChronology.INSTANCE, new Locale("SV", "SE")));

然而,对于一些地区(例如塞浦路斯英语en-CY),DateFormatDateTimeFormatter的结果不同。因此,如果您的目标是最大限度地确保向后兼容性,请使用过时的DateFormat类。

2
也许这并不重要,但我认为各种与语言环境相关的标准在语言代码中使用小写字母。所以也许应该是 new Locale("sv", "SE") - Basil Bourque
1
我也是这么想的,@BasilBourque,但是我直接从问题中把Locale原样拿了出来。我已经运行了代码,它可以工作。 - Ole V.V.
2
new Locale("SV", "SE").equals(new Locale("sv", "SE")) 返回 true,所以我认为这并不重要。@BasilBourque - Ole V.V.
1
参见 CLDR 与新的 SimpleDateFormat 对于 "y" 含义的冲突(摇头)。 - Meno Hochschild
3
注意:属性"java.locale.providers"只在Java运行时启动时读取,因此稍后调用System.setProperty()将不会产生效果。 (请参见LocaleServiceProvider API)。因此,在代码中设置此属性(如@OleV.V.所示的示例中)不是最佳实践,并且可能导致难以发现的错误。 - VinZ
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接