DateTimeFormatter 和 ZonedDateTime - 在不明确和不存在的日期时间 (DST) 上抛出异常
DateTimeFormatter and ZonedDateTime - Throw exception on ambiguous and nonexistent datetimes (DST)
我正在尝试创建一个非常严格的 DateTimeFormatter
/ZonedDateTime
工厂。如果 datetetime 没有意义,那么它应该抛出异常 - 没有调整。示例:如果在 DST 期间跳过一个小时。
目前这些测试失败,没有抛出异常。 ZonedDateTime guesses/adjusts 基于文档中描述的规则。
@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 中,但您可以轻松转换为 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]
我正在尝试创建一个非常严格的 DateTimeFormatter
/ZonedDateTime
工厂。如果 datetetime 没有意义,那么它应该抛出异常 - 没有调整。示例:如果在 DST 期间跳过一个小时。
目前这些测试失败,没有抛出异常。 ZonedDateTime guesses/adjusts 基于文档中描述的规则。
@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 中,但您可以轻松转换为 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]