有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用默认区域解析ZoneDateTime?

如何从不包含zone和其他字段的字符串中解析ZoneDateTime

以下是在斯波克进行的测试:

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:

  • 无法在索引23处分析“2014-04-23T04:30:45.123”
  • 无法在索引16处分析“2014-04-23T04:30”
  • 无法在索引10处解析“2014-04-23”

如何解析时间和区域设置为默认值的不完整日期


共 (2) 个答案

  1. # 1 楼答案

    格式化程序有一个withZone()method,可以调用它来提供缺少的时区

    ZonedDateTime.parse(
        value,
        DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(ZoneId.systemDefault()))
    

    请记住有一个bug,所以您需要8u20或更高版本才能让它完全工作

  2. # 2 楼答案

    由于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());