如何使用默认区域解析ZonedDateTime?
如何从不包含zone
和其他字段的字符串解析ZoneDateTime
?
这是在Spock中重现的测试:
import spock.lang.Specification import spock.lang.Unroll import java.time.ZoneId import java.time.ZoneOffset import java.time.ZonedDateTime import java.time.format.DateTimeFormatter @Unroll class ZonedDateTimeParsingSpec extends Specification { def "DateTimeFormatter.ISO_ZONED_DATE_TIME parsing incomplete date: #value #expected"() { expect: ZonedDateTime.parse(value, DateTimeFormatter.ISO_ZONED_DATE_TIME) == expected where: value | expected '2014-04-23T04:30:45.123Z' | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneOffset.UTC) '2014-04-23T04:30:45.123+01:00' | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneOffset.ofHours(1)) '2014-04-23T04:30:45.123' | ZonedDateTime.of(2014, 4, 23, 4, 30, 45, 123_000_000, ZoneId.systemDefault()) '2014-04-23T04:30' | ZonedDateTime.of(2014, 4, 23, 4, 30, 0, 0, ZoneId.systemDefault()) '2014-04-23' | ZonedDateTime.of(2014, 4, 23, 0, 0, 0, 0, ZoneId.systemDefault()) } }
前两个测试通过,其他所有测试都失败了DateTimeParseException:
- ‘2014-04-23T04:30:45.123’无法在索引23处解析
- ‘2014-04-23T04:30’无法在索引16处解析
- ‘2014-04-23’无法在索引10处解析
如何使用设置为默认值的时间和区域解析不完整的日期?
由于ISO_ZONED_DATE_TIME
格式化程序需要区域或偏移量信息,因此解析失败。 您必须创建一个DateTimeFormatter
,它包含区域信息和时间部分的可选部分。 逆向工程ZonedDateTimeFormatter
并添加可选标签并不太难。
然后使用parseBest()
方法解析String
。 然后,对于次优的解析结果,您可以使用您想要的任何默认值创建ZonedDateTime
。
DateTimeFormatter formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .append(ISO_LOCAL_DATE) .optionalStart() // time made optional .appendLiteral('T') .append(ISO_LOCAL_TIME) .optionalStart() // zone and offset made optional .appendOffsetId() .optionalStart() .appendLiteral('[') .parseCaseSensitive() .appendZoneRegionId() .appendLiteral(']') .optionalEnd() .optionalEnd() .optionalEnd() .toFormatter(); TemporalAccessor temporalAccessor = formatter.parseBest(value, ZonedDateTime::from, LocalDateTime::from, LocalDate::from); if (temporalAccessor instanceof ZonedDateTime) { return ((ZonedDateTime) temporalAccessor); } if (temporalAccessor instanceof LocalDateTime) { return ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault()); } return ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault());
格式化程序有一个withZone()
方法 ,可以调用它来提供缺少的时区。
ZonedDateTime.parse( value, DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(ZoneId.systemDefault()))
请记住,有一个错误,所以你需要8u20或更高版本才能完全运行。