【问题标题】:DateTimeFormatter and ZonedDateTime - Throw exception on ambiguous and nonexistent datetimes (DST)DateTimeFormatter 和 ZonedDateTime - 在不明确和不存在的日期时间 (DST) 上引发异常
【发布时间】:2020-08-11 11:32:12
【问题描述】:

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

目前这些测试失败,没有抛出异常。 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 按照文档中的说明进行调整。我想改变这种行为,以便在不完全清楚的时候抛出。

【问题讨论】:

  • 你在问什么?此代码是否根据测试工作?如果不是,它有什么作用?如果是,你是在问这是否足够?
  • 我希望测试通过。目前他们失败了 - 没有抛出异常。 ZonedDateTime 按照文档中的说明进行调整。我想改变这种行为,以便在不完全清楚的任何时候抛出。

标签: java datetime kotlin timezone dst


【解决方案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;
}

测试

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]

【讨论】:

    猜你喜欢
    • 2015-07-08
    • 2016-04-05
    • 2021-06-18
    • 2015-07-16
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    相关资源
    最近更新 更多