【问题标题】:How can I validate a local date time within daylight savings time?如何在夏令时验证本地日期时间?
【发布时间】:2017-08-29 00:15:47
【问题描述】:

Mar 12, 2017 02:39:00 "America/Chicago" 不存在。当我将日期和时间设置为此值时,它不会失败。一小时后,时间设置为Mar 12, 2017 03:39:00。如何通知我这个时间不存在。这是时间向前跳跃的方式

01:59:59
3:00:00

如您所见,02:39:00 在该日期永远不会存在。

这是我正在使用的代码

package com.company;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {

    public static void main(String[] args) {
        ZoneId zoneId = ZoneId.of("America/Chicago");
        ZonedDateTime dateTimeStart = ZonedDateTime.of(2017, 1, 1, 15, 39, 0, 0, ZoneId.of("America/Chicago"));
        ZonedDateTime dateTimeStartUtc = dateTimeStart.withZoneSameInstant(ZoneOffset.UTC);

        ZoneId zoneIdDst = ZoneId.of("America/Chicago");
        ZonedDateTime dateTimeStartDst = ZonedDateTime.of(2017, 3, 12, 2, 39, 0, 0, ZoneId.of("America/Chicago"));
        ZonedDateTime dateTimeStartUtcDst = dateTimeStart.withZoneSameInstant(ZoneOffset.UTC);
        int y = 90;
    }
}

【问题讨论】:

  • 这是 ZonedDateTime 根据to the documentation 的预期行为。您将不得不使用不同的类。

标签: java java-8 java-time


【解决方案1】:

您的示例不会引发异常,因为ZonedDateTime.of(..) 会调整日期时间。 javadoc 状态

这将创建一个与输入本地日期时间匹配的分区日期时间 尽可能密切。时区规则,例如夏令时,意味着 并非每个本地日期时间都对指定区域有效,因此 可以调整本地日期时间。

您可以使用ZonedDateTime#ofStrict(LocalDateTime, ZoneOffset, ZoneId) 来执行验证。

获取 ZonedDateTime 的实例,严格验证 本地日期时间、偏移量和区域 ID 的组合。

这会创建一个分区日期时间,以确保偏移量适用于 根据指定区域的规则的本地日期时间。如果 偏移量无效,抛出异常。

您首先需要构造一个LocalDateTime。然后,您将获得该本地日期时间的ZoneIdZoneOffset。然后你可以将这三个都提供给ofStrict

例如,

ZoneId zoneId = ZoneId.of("America/Chicago");
LocalDateTime ldt = LocalDateTime.of(2017, 3, 12, 2, 39, 0, 0);
ZoneOffset zoneOffset = zoneId.getRules().getOffset(ldt);
ZonedDateTime zdt = ZonedDateTime.ofStrict(ldt, zoneOffset, zoneId);

会抛出

Exception in thread "main" java.time.DateTimeException: LocalDateTime '2017-03-12T02:39' does not exist in zone 'America/Chicago' due to a gap in the local time-line, typically caused by daylight savings
    at java.time.ZonedDateTime.ofStrict(ZonedDateTime.java:484)

【讨论】:

    【解决方案2】:

    这里是一个没有抛出异常的验证。您只需要询问区域规则LocalDateTime 在给定时区内是否有效:

    public static boolean isValid(LocalDateTime ldt, ZoneId zoneId) {
        return !zoneId.getRules().getValidOffsets(ldt).isEmpty();
    }
    

    【讨论】:

    • 请注意,此方法将返回true,即使在给定时间有多个有效偏移量的情况下也是如此。例如,当时钟从 04:00->03:00 倒转一小时时,时间 03:30 将出现两次,有两个不同的偏移量。如果您还想检测这种情况,请将isValid 方法更改为返回true,仅在偏移列表只有一个值的情况下:return zoneId.getRules().getValidOffsets(ldt).size() == 1;
    • @anddero 但是LocalDateTime 与两个有效偏移量的组合仍应被视为有效,这意味着它存在于现实世界中(在两个不同的时刻两次)。
    • 它可能是有效的,但它比没有有效的偏移量更危险。如果时钟在 03:00->04:00 时调快,那么 03:30 的时间对于忘记调时的人来说可能有意义。它只是意味着04:30。因此,每个将时间 03:30 输入某个 Web 服务的人,它都会自动为每个用户翻译成相同的瞬间。但是如果时钟倒转 04:00->03:00,一个用户的 03:30 可能与另一个用户的 03:30 不一样,所以在预约医生的情况下,患者可能会错过一个小时的会议.
    • 我知道你在谈论一个时间的存在。我只是评论说,如果 user input 被验证,那么两个输入都应该被认为是错误的,并且应该通知用户。对于模棱两可的输入,他们应该明确说明他们想要使用哪个有效变体。
    猜你喜欢
    • 2012-04-07
    • 2012-07-09
    • 2015-07-09
    • 2017-08-28
    • 2015-05-29
    • 2014-03-02
    • 2016-02-13
    • 2022-09-23
    • 2015-05-03
    相关资源
    最近更新 更多