java - 如何使用 DateTimeFormatter 解析非标准月份名称

标签 java datetime localization java-8 java-time

我需要解析以下形式的(德语)日期:

10. Jan. 18:14
8. Feb. 19:02
1. Mär. 19:40
4. Apr. 18:55
2. Mai 21:55
5. Juni 08:25
5. Juli 20:09
1. Aug. 13:42
[...]

如您所见,如果月份超过 4 个字符,月份名称将被截断。更奇怪的是,不要问我为什么,三月缩写为 Mär.,尽管整个名称是 März。我如何用 java.time 解析它? (日期的格式基于创建日期列表的 Android 设备的本地化。但是,我没有在 Android 上解析它)

我的方法是像这样创建一个 DateTimeFormatter:

DateTimeFormatter.ofPattern("d. MMMM HH:mm").withLocale(Locale.GERMAN);
// or
DateTimeFormatter.ofPattern("d. MMMMM HH:mm").withLocale(Locale.GERMAN);

但是 MMMMMMMMM 模式都不适合缩短的日期。当然,我可以使用以下模式 d。嗯。 HH:mm 以匹配缩短的月份,但我无法匹配 3 和 4 个字符的月份。我知道我可以有两个格式化程序(MMM. 和 MMMMM),但我宁愿有一个解决方案,我只有一个格式化程序,可能还有一个自定义语言环境或类似的东西。

最佳答案

问题的答案是DateTimeFormatterBuilder类和 appendText(TemporalField, Map)方法。它允许任何文本在格式化或解析时与一个值相关联,从而有效而优雅地解决了这个问题:

Map<Long, String> monthNameMap = new HashMap<>();
monthNameMap.put(1L, "Jan.");
monthNameMap.put(2L, "Feb.");
monthNameMap.put(3L, "Mar.");
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    .appendPattern("d. ")
    .appendText(ChronoField.MONTH_OF_YEAR, monthNameMap)
    .appendPattern(" HH:mm")
    .parseDefaulting(ChronoField.YEAR, 2016)
    .toFormatter();

System.out.println(LocalDateTime.parse("10. Jan. 18:14", fmt));
System.out.println(LocalDateTime.parse("8. Feb. 19:02", fmt));

一些注意事项:

  • monthNameMap 必须填充所有 12 个月
  • 格式化程序通常应该分配给静态最终常量,而不是一直创建
  • 已添加 parseDefaulting(YEAR, 2016) 以便可以直接使用 LocalDateTime.parse(String, DateTimeFormatter)。没有它,就不会有年份,因此只能解析 TemporalAccessor(年份必须是闰年,以防解析 29th Feb)

关于java - 如何使用 DateTimeFormatter 解析非标准月份名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30816016/

相关文章:

java - 在 Redis 集合中表示空集合

javascript - 应用程序脚本从 Date() 转换为可读的内容

android - 更改 android 应用内产品的默认语言

ios - 本地化非根 InfoPlist 值

c# - 如何在周末在 C# 中分配唯一的员工

c# - Xamarin.mac 资源本地化不会因当前文化而改变

Android Studio 上的 Java Reflect 无法找到要调用的公共(public)静态方法

java - Horizo​​ntalLayout 带有包装组件?

java - 如何使 mouseClicked 像 mousePressed 一样工作

ruby-on-rails - 为什么这两个日期时间不同?