【问题标题】:Java ZonedDateTime to Instant conversionJava ZonedDateTime 到即时转换
【发布时间】:2018-08-12 11:24:16
【问题描述】:

我打算按照以下逻辑将 ZonedDateTime 转换为即时。

说,我在 PST 时区,当前时间是上午 11 点。如果我现在转换(截至 2018 年 3 月 4 日没有夏令时)并且 toInstant 将是晚上 7 点。

对于同样的上午 11 点,toInstant 将在 2018 年 4 月 4 日下午 6 点返回,因为将遵守夏令时。

所以,下面的代码正确返回。

ZonedDateTime dateTime = ZonedDateTime.now();  --->>> March 04th 2018 at 11 A.M PST
dateTime.plusMonths(1).toInstant(); -->> returns April 04th 2018 at 6 PM PST as daylight saving will be observed

但是,

如果我转换为 Instant 然后添加一个月,结果会有所不同。

Instant dateTime = ZonedDateTime.now().toInstant();  --->>> March 04th 2018 at 7 P.M UTC
dateTime.plus(1,ChronoUnit.MONTHS).toInstant(); -->> returns April 04th 2018 at 7 PM UTC ( but the actual time should be 6 PM UTC ). 

这没关系,因为我们已经转换为 UTC,它只是从那里添加。

因此,要包括夏令时,我需要在 ZonedDateTime 中添加天、月或年 ....,然后转换为 Instant。

ZonedDateTime dateTime = ZonedDateTime.now();   ---> March 04th 2018 at 11A.M
dateTime.plusDays(10).toInstant();     ---> March 14th 2018 at 6P.M
dateTime.plusMonths(1).toInstant();     ---> April 04th 2018 at 6P.M

上面的代码按预期工作。但是下面的不是返回 6P.M,而是返回 7P.M.

dateTime.plusSeconds(org.joda.time.Period.days(1).multipliedBy(10).toStandardSeconds().getSeconds())
         .toInstant())  --> ---> March 14th 2018 at 7P.M

不确定,这有什么问题以及如何让它在几秒钟内工作。

【问题讨论】:

  • 没有ZoneDateTime 类和Period 没有public days 工厂方法。您使用的不是 Java 的 API 吗?也没有toStandardSeconds 方法。
  • 对不起,错字,...它是 ZonedDateTime 和 Period 来自 joda.time。立即更新问题。
  • 这更有意义,但是像这样混合两个 API 必然会产生意想不到的结果。我建议您尝试使用 just Java 的 API 重新创建问题。
  • 由于其他一些限制,我正在使用 joda.time。
  • 这可以仅使用 Java 8 java.time 方法重现。调用 Instant plusTenDaysInSeconds = zonedDateTime.plusSeconds(Duration.ofDays(10).getSeconds()).toInstant(); 得到 2018-03-14T19:00:00Z,但调用 Instant plusTenDays = zonedDateTime.plusDays(10).toInstant(); 得到 2018-03-14T18:00:00Z。

标签: java java-8 jodatime


【解决方案1】:

原因可在ZonedDateTime 类的文档中找到。对于方法plusDays,我们在方法文档中看到了这一点:

这在本地时间线上运行,将天数添加到本地日期时间。然后将其转换回 ZonedDateTime,使用区域 ID 获取偏移量。

转换回 ZonedDateTime 时,如果本地日期时间重叠,则尽可能保留偏移量,否则将使用较早的偏移量。如果在间隙中,本地日期时间将根据间隙长度向前调整。

但是,在plusSeconds 方法的文档中,我们看到了这一点:

这在即时时间线上运行,因此增加一秒总是会延迟一秒。这可能会导致本地日期时间的变化量不是一秒。请注意,这与日、月和年使用的方法不同。

因此,这两种方法的设计行为不同,您在选择使用哪种方法来满足您的目的时需要考虑这一点。

【讨论】:

  • 我的要求是在 ZonedDateTime 中添加分钟或小时天或月。它适用于 plusDays,plusMonths。但是,我怎样才能使它适用于 plusHours 和 plusMinutes .... plusHours 仍然无法按预期工作....
【解决方案2】:

据我了解您的要求,例如,您可以增加几分钟或几小时的时间

    long minutesToAdd = Duration.ofDays(10).toMinutes();

我正在使用 java.time,因为我没有使用 Joda-Time 的经验。如果你愿意的话,也许你可以把我的想法翻译成 Joda-Time。

据我进一步了解,添加上述分钟的结果应该是该分钟后的时间点。相反,它应该与添加 10 天相同。因此,如果现在是加利福尼亚州的晚上 9 点,那么您希望 10 天后的加利福尼亚州是晚上 9 点。我建议您通过在添加分钟或小时之前转换为LocalDateTime 来解决此问题,然后再转换回ZonedDateTime

    ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Los_Angeles"));
    System.out.println(now);
    System.out.println(now.toInstant());
    Instant inTenDays = now.toLocalDateTime()
            .plusMinutes(minutesToAdd)
            .atZone(now.getZone())
            .toInstant();
    System.out.println(inTenDays);

这是刚刚打印出来的

2018-03-04T21:16:19.187690-08:00[America/Los_Angeles]
2018-03-05T05:16:19.187690Z
2018-03-15T04:16:19.187690Z

由于夏令时 (DST) 于 3 月 15 日生效(从今年 3 月 11 日开始),因此您不会在 UTC 中获得相同的小时,而是在 UTC 中获得相同的小时你的时区。

【讨论】:

    猜你喜欢
    • 2021-07-25
    • 2019-01-21
    • 2017-05-31
    • 1970-01-01
    • 2018-12-24
    • 2015-11-07
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多