如何解析"2021-11-20+01:00"格式日期字符串为ZonedDateTime?
问题原因
解析失败的核心是你要构造的ZonedDateTime/OffsetDateTime属于带时间的日期类型,必须要有完整的时分秒时间信息才能实例化,而你传入的字符串2021-11-20+01:00仅包含日期+时区偏移两个维度的信息,缺少时间部分:
- 你使用的
yyyy-MM-ddxxx格式和DateTimeFormatter.ISO_OFFSET_DATE格式化器本身就是为「日期+偏移」设计的,只会解析日期和偏移字段,不会补全缺失的时间字段。 - 报错里的
Unsupported field: InstantSeconds就是因为缺少时分秒信息,Java无法计算出对应时间的时间戳秒数,也就无法构造Instant进而实例化OffsetDateTime/ZonedDateTime。 - 你查询的Javadoc描述是正确的,三个
x确实支持带冒号的时区偏移格式,偏移部分的解析没有问题,问题和偏移格式无关。
解决方法
根据你的业务需求可以选择以下任意一种方案:
方案1:先解析字段再手动拼接
先分别解析出日期和偏移,手动补全默认时间后构造目标类型:
String value = "2021-11-20+01:00"; TemporalAccessor parsedResult = DateTimeFormatter.ISO_OFFSET_DATE.parse(value); LocalDate date = LocalDate.from(parsedResult); ZoneOffset offset = ZoneOffset.from(parsedResult); // 补默认0点构造OffsetDateTime OffsetDateTime offsetDateTime = date.atStartOfDay(offset); // 转ZonedDateTime ZonedDateTime zonedDateTime = offsetDateTime.toZonedDateTime();
方案2:给格式化器配置默认时间值
用DateTimeFormatterBuilder自定义格式化器,给缺失的时间字段设置默认值,可直接解析为目标类型:
DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("yyyy-MM-ddxxx") // 配置缺失的时分秒默认值为0 .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) .toFormatter(); String value = "2021-11-20+01:00"; OffsetDateTime offsetDateTime = OffsetDateTime.parse(value, formatter); ZonedDateTime zonedDateTime = ZonedDateTime.parse(value, formatter);
方案3:补全字符串后直接解析
在原字符串的日期和偏移之间插入默认的时间部分,变成标准ISO带偏移日期时间格式后直接解析:
String value = "2021-11-20+01:00"; // 插入时间部分,拼接后格式为2021-11-20T00:00:00+01:00 String fullTimeStr = value.replace("+", "T00:00:00+"); OffsetDateTime offsetDateTime = OffsetDateTime.parse(fullTimeStr);
以上三种方案均兼容OpenJDK 11版本,可直接运行。
内容的提问来源于stack exchange,提问作者Ernestas Gruodis
相关产品推荐
相关产品推荐

