Java时间解析具有短日期名称的日期

我有以下德国日期:So,18 Jul 2021 15:24:00 +0200

我无法使用 Java Time 解析它:

DateTimeFormatter.ofPattern("EEE,dd MMM yyyy HH:mm:ss Z",Locale.GERMANY)
  .parse("So,18 Jul 2021 15:24:00 +0200",Instant::from)

当它抛出时:Text 'So,18 Jul 2021 15:24:00 +0200' could not be parsed at index 0

如果我将字符串更改为正确格式,它可以工作:

-So,18 Jul 2021 15:24:00 +0200
+So.,18 Juli 2021 15:24:00 +0200

有什么神奇的模式可以解析上面的日期吗?


我在其他日期也遇到了同样的问题

  • LocalDateTime.parse("ven,16/07/2021 - 09:49",DateTimeFormatter.ofPattern("EE,dd/MM/yyyy - HH:mm",Locale("fr")))
    • ven 必须是 ven.
  • LocalDateTime.parse("vr,23 apr 2021 17:04:00",dd MM yyyy HH:mm:ss",Locale("nl")))
    • apr 必须是 04(为了使用 MM
wssfeng8287 回答:Java时间解析具有短日期名称的日期

为星期几指定自己的缩写

根据 CLDR,德语星期几的缩写用点表示。要让 Java 解析缩写缺少点的字符串,有两个明显的解决方案:

  1. 不要使用 CLDR。 Java 8 及之前版本中的 Java 缩写没有点,并且在较新的 Java 版本中仍然可用。
  2. 指定您自己的缩写。

由于法语有类似问题,Java自己的缩写也有点,我建议解决方案1.对你来说是不够的。因此,让我们深入研究解决方案 2。我下面的代码采用 CLDR 的缩写,例如 So.,并从中删除尾随点,因此您将获得例如 So 作为您的字符串。

    Locale loc = Locale.GERMANY;
    Map<Long,String> dowsWithoutDots = Arrays.stream(DayOfWeek.values())
            .collect(Collectors.toMap(dow -> Long.valueOf(dow.getValue()),dow -> dow.getDisplayName(TextStyle.SHORT,loc).replaceFirst("\\.$","")));
    Map<Long,String> monthsWithoutDots = Arrays.stream(Month.values())
            .collect(Collectors.toMap(m -> Long.valueOf(m.getValue()),m -> m.getDisplayName(TextStyle.SHORT,loc).substring(0,3)));
    DateTimeFormatter germanWithoutDots = new DateTimeFormatterBuilder()
            .appendText(ChronoField.DAY_OF_WEEK,dowsWithoutDots)
            .appendPattern(",dd ")
            .appendText(ChronoField.MONTH_OF_YEAR,monthsWithoutDots)
            .appendPattern(" yyyy HH:mm:ss Z")
            .toFormatter(loc);
    
    System.out.println(germanWithoutDots.parse("So,18 Jul 2021 15:24:00 +0200",Instant::from));

片段的输出是:

2021-07-18T13:24:00Z

删除最后一个点的月份缩写不起作用,因为正如您所观察到的,CLDR 的缩写是 Juli,其中您有 Jul。因此,我没有删除点,而是将其缩写为三个字符。您应该测试它是否适用于所有月份(包括 Mai)。

我没有为法语和荷兰语尝试过相同的方法,但应该可以。

如果您想试试解决方案 1. 的运气,完全绕过 CLDR,请参阅JDK dateformatter parsing DayOfWeek in German locale,java8 vs java9

,

现代 Date-Time API 对模式非常讲究。因此,创建可用于解析所有类型字符串的单一模式几乎是不可能的。然而,DateTimeFormatter 的最大特点之一是它可以灵活地使用可选模式,使用方括号指定,例如下面的演示使用 E,d [MMMM][MMM][M] u H:m:s Z,它具有三个可选的月份模式。

演示:

import java.time.DateTimeException;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.stream.Stream;


public class Main {
    public static void main(String[] args) {
        Stream.of(
                "So.,18 Juli 2021 15:24:00 +0200","ven.,16 avr. 2021 15:24:00 +0200","vr,16 apr. 2021 15:24:00 +0200",16 07 2021 15:24:00 +0200"
        ).forEach(s -> {
            Stream.of(
                    Locale.GERMANY,Locale.FRANCE,new Locale("nl","NL")
            ).forEach( locale -> {
                try {
                    System.out.println("Parsed '" + s + "' using the locale," + locale + " => " + parseToInstant(s,locale));
                }catch(DateTimeException e) {
                    //....
                }
            });
        });
    }

    static Instant parseToInstant(String strDateTime,Locale locale) {
        return DateTimeFormatter.ofPattern("E,d [MMMM][MMM][M] u H:m:s Z").withLocale(locale).parse(strDateTime,Instant::from);
    }
}

输出:

Parsed 'So.,18 Juli 2021 15:24:00 +0200' using the locale,de_DE => 2021-07-18T13:24:00Z
Parsed 'ven.,16 avr. 2021 15:24:00 +0200' using the locale,fr_FR => 2021-04-16T13:24:00Z
Parsed 'vr,16 apr. 2021 15:24:00 +0200' using the locale,nl_NL => 2021-04-16T13:24:00Z
Parsed 'vr,16 07 2021 15:24:00 +0200' using the locale,nl_NL => 2021-07-16T13:24:00Z

ONLINE DEMO

DateTimeFormatterBuilder 中了解有关日期-时间模式的更多信息。

本文链接:https://www.f2er.com/5883.html

大家都在问