Java ZonedDateTime 到即时转换
Java ZonedDateTime to Instant conversion
我计划按照以下逻辑将 ZonedDateTime 转换为即时。
说,我在 PST 时区,当前时间是 11A.M。如果我现在转换(截至今天 2018 年 3 月 4 日没有夏令时)并且 toInstant 将是 7P.M.
对于相同的 11 A.M,自 2018 年 4 月 4 日起,toInstant 将 return 6 P.M,因为将遵守夏令时。
因此,下面的代码 return 是正确的。
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
以上代码按预期工作。但是下面的不是returning 6P.M,而是returns 7P.M.
dateTime.plusSeconds(org.joda.time.Period.days(1).multipliedBy(10).toStandardSeconds().getSeconds())
.toInstant()) --> ---> March 14th 2018 at 7P.M
不确定,这有什么问题以及如何让它与秒一起工作。
原因可在 ZonedDateTime
class 的文档中找到。对于方法plusDays
,我们在方法文档中看到:
This operates on the local time-line, adding days to the local date-time. This is then converted back to a ZonedDateTime, using the zone ID to obtain the offset.
When converting back to ZonedDateTime, if the local date-time is in an overlap, then the offset will be retained if possible, otherwise the earlier offset will be used. If in a gap, the local date-time will be adjusted forward by the length of the gap.
但是,在 plusSeconds
方法的文档中,我们看到:
This operates on the instant time-line, such that adding one second will always be a duration of one second later. This may cause the local date-time to change by an amount other than one second. Note that this is a different approach to that used by days, months and years.
因此这两种方法的行为设计不同,您在选择适合您目的的方法时需要考虑这一点。
据我了解您的要求,例如您可以增加几分钟或几小时的时间
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 中得到的不是相同的 hour-of-day,而是相同的 hour-of-day 在您的时区。
我计划按照以下逻辑将 ZonedDateTime 转换为即时。
说,我在 PST 时区,当前时间是 11A.M。如果我现在转换(截至今天 2018 年 3 月 4 日没有夏令时)并且 toInstant 将是 7P.M.
对于相同的 11 A.M,自 2018 年 4 月 4 日起,toInstant 将 return 6 P.M,因为将遵守夏令时。
因此,下面的代码 return 是正确的。
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
以上代码按预期工作。但是下面的不是returning 6P.M,而是returns 7P.M.
dateTime.plusSeconds(org.joda.time.Period.days(1).multipliedBy(10).toStandardSeconds().getSeconds())
.toInstant()) --> ---> March 14th 2018 at 7P.M
不确定,这有什么问题以及如何让它与秒一起工作。
原因可在 ZonedDateTime
class 的文档中找到。对于方法plusDays
,我们在方法文档中看到:
This operates on the local time-line, adding days to the local date-time. This is then converted back to a ZonedDateTime, using the zone ID to obtain the offset.
When converting back to ZonedDateTime, if the local date-time is in an overlap, then the offset will be retained if possible, otherwise the earlier offset will be used. If in a gap, the local date-time will be adjusted forward by the length of the gap.
但是,在 plusSeconds
方法的文档中,我们看到:
This operates on the instant time-line, such that adding one second will always be a duration of one second later. This may cause the local date-time to change by an amount other than one second. Note that this is a different approach to that used by days, months and years.
因此这两种方法的行为设计不同,您在选择适合您目的的方法时需要考虑这一点。
据我了解您的要求,例如您可以增加几分钟或几小时的时间
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 中得到的不是相同的 hour-of-day,而是相同的 hour-of-day 在您的时区。