如何从字符串“06.03.2018 06:00 CET”获得{Zoned,Offset} DateTime?

时间:2018-04-27 09:36:39

标签: java java-time java-date

我正在尝试解析来自欧洲RSS Feed的日期时间。日期如下所示:"06.03.2018 06:00 CET"。我想要ZonedDateTimeOffsetDateTime,但我不能说服Java解析String。我做错了什么?

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.YYYY HH:mm z");
ZonedDateTime zdt = ZonedDateTime.parse("06.03.2018 06:00 CET", dtf);

Caused by: java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: {WeekBasedYear[WeekFields[SUNDAY,1]]=2018, MonthOfYear=3, DayOfMonth=6},ISO,Europe/Paris resolved to 06:00 of type java.time.format.Parsed

// seems to be crashing here:  LocalDate.java:363
public static LocalDate from(TemporalAccessor temporal) {
    Objects.requireNonNull(temporal, "temporal");
    LocalDate date = temporal.query(TemporalQueries.localDate());
    if (date == null) {  // <== SOMEHOW THIS IS NULL
        throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " +
                temporal + " of type " + temporal.getClass().getName());
    }
    return date;
}

temporal的值为:

{WeekBasedYear[WeekFields[SUNDAY,1]]=2018, MonthOfYear=3, DayOfMonth=6},ISO,Europe/Paris resolved to 06:00

1 个答案:

答案 0 :(得分:2)

大写Y代表基于周的年份(有关详细说明,请参阅here),而年份字段由小写y表示。有关详细信息,请参阅javadoc: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns

所以将你的模式改为“dd.MM。 yyyy HH:mm z”。

另一个细节是时区缩写不明确。 CET由多个国家/地区使用,因此可以映射到多个时区:https://www.timeanddate.com/time/zones/cet#tz-where

某些缩写可能有用(又名“不会抛出异常”),但它们会映射到您无法控制的任意默认值。在我的JVM中,运行此代码:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm z");
ZonedDateTime zdt = ZonedDateTime.parse("06.03.2018 06:00 CET", dtf);

生成ZonedDateTime等于:

  

2018-03-06T06:00 + 01:00 [欧洲/巴黎]

CET被映射到“欧洲/巴黎”(这是JVM的一些任意选择,但它不能保证你总能得到它)。 CET也被许多其他时区使用,例如“欧洲/柏林”,“欧洲/马德里”等等。

如果您想在缩写时准确控制所需的时区,可以创建一个包含您选择的集合,并使用DateTimeFormatterBuilder创建DateTimeFormatter

// set of preferred zones
Set<ZoneId> preferredZones = new HashSet<ZoneId>();
// my arbitrary choice for CET
preferredZones.add(ZoneId.of("Europe/Berlin"));
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
    // date/time
    .appendPattern("dd.MM.yyyy HH:mm ")
    // zone names
    .appendZoneText(TextStyle.SHORT, preferredZones)
    // create formatter
    .toFormatter(Locale.US);

ZonedDateTime zdt = ZonedDateTime.parse("06.03.2018 06:00 CET", dtf);

现在ZonedDateTime将设置为我在我的首选区域中选择的时区:

  

2018-03-06T06:00 + 01:00 [欧洲/柏林]