DateTimeFormatter和ZonedDateTime-对不明确和不存在的日期时间(DST)抛出异常

问题描述 投票:0回答:1

我正在尝试创建一个非常严格的DateTimeFormatter / ZonedDateTime工厂。如果datetetime没有意义,则应该抛出异常-无调整。例如:如果在夏令时期间跳过一个小时。

目前这些测试失败,不会引发异常。 ZonedDateTime根据文档中所述的规则进行猜测/调整。

    @Test
    fun `Ambiguous hour during  +0200 to +0100 DST change`() {
        val input = "2019-10-27T02:30:00Europe/Prague"
        val formatter = createFormatter()

        Assertions.assertThrows(DateTimeParseException::class.java) {
            ZonedDateTime.from(formatter.parse(input))
            // Gets instead adjusted as 2019-10-27T02:30:00Europe/Prague+02:00

        }
    }

    @Test
    fun `Skipped hour during +0100 to +0200 DST change`() {
        val formatter = createFormatter()

        Assertions.assertThrows(DateTimeParseException::class.java) {
            ZonedDateTime.from(formatter.parse("2019-03-31T02:30:00Europe/Prague"))
            // Gets instead adjusted as 2019-03-31T03:30:00Europe/Prague+02:00
        }
    }


    @Test
    fun `Test impossible offset during DST change`() {
        val input = "2019-10-27T02:30:00Europe/Prague+05:00"
        val formatter = createFormatter()

        Assertions.assertThrows(DateTimeParseException::class.java) {
            ZonedDateTime.from(formatter.parse(input))
            // Gets instead  adjusted as 2019-10-26T23:30:00Europe/Prague+02:00
        }
    }

Europe/Prague区域的更改来自here

我拥有的代码:

fun createFormatter(): DateTimeFormatter {
    return DateTimeFormatterBuilder()
        .parseCaseSensitive()
        .parseStrict()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .appendZoneRegionId()
        .optionalStart()
        .appendOffsetId()
        .optionalEnd()
        .toFormatter()
        .withResolverStyle(ResolverStyle.STRICT)
}

ZonedDateTime进行调整,如文档中所述。我想将这种行为更改为在任何不完全清楚的时候抛出。

java datetime kotlin timezone dst
1个回答
1
投票

您需要添加额外的逻辑来验证结果。

下面的代码是Java的,但是您可以轻松地转换为Kotlin。

static ZonedDateTime parseVeryStrict(String text) {
    TemporalAccessor parsed = createFormatter().parse(text);
    ZonedDateTime zonedDateTime = ZonedDateTime.from(parsed);

    if (parsed.isSupported(OFFSET_SECONDS)) {
        // Verify given offset was correct
        ZoneOffset zoneOffset = ZoneOffset.from(parsed);
        if (! zoneOffset.equals(zonedDateTime.getOffset()))
            throw new DateTimeParseException("Incorrect offset: '" + text + "'", text, 0);
    } else {
        // Without offset, fail if in DST overlap time range
        if (! zonedDateTime.withEarlierOffsetAtOverlap().isEqual(zonedDateTime.withLaterOffsetAtOverlap()))
            throw new DateTimeParseException("Ambiguous time (DST overlap): '" + text + "'", text, 0);
    }

    // Verify time wasn't adjusted because it was in DST gap time range
    LocalTime localTime = LocalTime.from(parsed);
    if (! localTime.equals(zonedDateTime.toLocalTime()))
        throw new DateTimeParseException("Invalid time (DST gap): '" + text + "'", text, 0);

    return zonedDateTime;
}

Test

public static void main(String[] args) {
    test("2019-10-27T02:30:00");
    test("2019-10-27T02:30:00Europe/Prague");
    test("2019-03-31T02:30:00Europe/Prague");
    test("2019-10-27T02:30:00Europe/Prague+05:00");
    test("2019-10-27T02:30:00Europe/Prague+02:00");
    test("2019-10-27T02:30:00Europe/Prague+01:00");
}

static void test(String text) {
    try {
        System.out.println(text + " -> " + parseVeryStrict(text));
    } catch (DateTimeParseException e) {
        System.out.println(text + " - " + e.getMessage());
    }
}

输出

2019-10-27T02:30:00 - Text '2019-10-27T02:30:00' could not be parsed at index 19
2019-10-27T02:30:00Europe/Prague - Ambiguous time (DST overlap): '2019-10-27T02:30:00Europe/Prague'
2019-03-31T02:30:00Europe/Prague - Invalid time (DST gap): '2019-03-31T02:30:00Europe/Prague'
2019-10-27T02:30:00Europe/Prague+05:00 - Incorrect offset: '2019-10-27T02:30:00Europe/Prague+05:00'
2019-10-27T02:30:00Europe/Prague+02:00 -> 2019-10-27T02:30+02:00[Europe/Prague]
2019-10-27T02:30:00Europe/Prague+01:00 -> 2019-10-27T02:30+01:00[Europe/Prague]
© www.soinside.com 2019 - 2024. All rights reserved.