我正在尝试解析来自欧洲RSS feed的日期时间。日期看起来像这样:"06.03.2018 06:00 CET"
。我想要一个ZonedDateTime
或OffsetDateTime
,但是我不能说服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
最佳答案
大写字母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 [欧洲/柏林]