如何从不包含 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 处解析
- 无法在索引 10 处解析“2014-04-23”
如何解析时间和时区设置为默认值的不完整日期?
最佳答案
由于 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());
关于java - 如何使用默认区域解析 ZonedDateTime?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27293994/