如何从字符串“06.03.2018 06:00 CET”获取 {Zoned,Offset}DateTime?
How do I get a {Zoned,Offset}DateTime from String "06.03.2018 06:00 CET"?
我正在尝试解析来自欧洲 RSS 提要的日期时间。日期如下所示:"06.03.2018 06:00 CET"
。我想要 ZonedDateTime
或 OffsetDateTime
,但我无法说服 Java 解析字符串。我做错了什么?
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
大写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
一些缩写可能有效(又名 "doesn't throw exception"),但它们将被映射到一些您无法控制的任意默认值。在我的 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[Europe/Paris]
CET 被映射到 "Europe/Paris"(这是 JVM 的一些任意选择,但不能保证您总能得到它)。 CET 也被许多其他时区使用,例如 "Europe/Berlin"、"Europe/Madrid" 和许多其他时区。
如果您想在出现缩写时准确控制您想要的时区,您可以创建一个带有您的选择的集合并使用 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[Europe/Berlin]
我正在尝试解析来自欧洲 RSS 提要的日期时间。日期如下所示:"06.03.2018 06:00 CET"
。我想要 ZonedDateTime
或 OffsetDateTime
,但我无法说服 Java 解析字符串。我做错了什么?
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
大写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
一些缩写可能有效(又名 "doesn't throw exception"),但它们将被映射到一些您无法控制的任意默认值。在我的 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[Europe/Paris]
CET 被映射到 "Europe/Paris"(这是 JVM 的一些任意选择,但不能保证您总能得到它)。 CET 也被许多其他时区使用,例如 "Europe/Berlin"、"Europe/Madrid" 和许多其他时区。
如果您想在出现缩写时准确控制您想要的时区,您可以创建一个带有您的选择的集合并使用 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[Europe/Berlin]