1

我正在测试"2016-03-28T02:00:00+0200"(1459123200 in UTC Sec.)

减去 1 天后,应用 DST,输出应为:

“2016-03-27T03:00:00+0200”

但我得到了这个:

2016-03-26T01:00+01:00[欧洲/斯德哥尔摩]

代码:

public class DateFormatSampleCode {
    public static void main(String[] args) 
    {
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(1459123200, 0, ZoneOffset.UTC);

        System.out.println(localDateTime);
        localDateTime = localDateTime.minusDays(1);
        System.out.println(localDateTime);

        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Europe/Stockholm"));

        System.out.println(zonedDateTime);
    }
}

请检查并指出我哪里出错了。

4

2 回答 2

2

很好,您找到了解决方案,我只想添加一些见解并建议对您的答案进行一些改进。

使用设置 JVM 默认时区TimeZone.setDefault并不是实现此目的的最佳方法。尽管它可能在大多数情况下都有效,但如果您认为此代码在更复杂的环境中运行,它会有点风险且容易出错。

那是因为TimeZone.setDefault更改了整个JVM 的默认时区。在同一个 JVM 中运行的任何其他应用程序都会受到它的影响。同一个应用程序的其他部分也会受到影响,即使是在多个线程中运行的相同代码也可能会给您错误的结果(并且竞争条件很难调试)。

我注意到您正在使用TimeZone.setDefault(TimeZone.getTimeZone(timezone));. 这意味着您已经在使用特定的时区,因此无需依赖 JVM 的默认值。如果您有特定的时区名称,请使用它而不是默认名称。所以我建议你addDays方法应该是这样的:

public ZonedDateTime addDays(long myUTCTimeInSeconds, int days, String timezone) {
    // get the instant from the UTC seconds
    Instant instant = Instant.ofEpochSecond(myUTCTimeInSeconds);
    // get the instant at the specified timezone
    ZonedDateTime z = instant.atZone(ZoneId.of(timezone));

    // add days
    return z.plusDays(days);
}

所做的改进:

  • plusDays如果你通过它已经减去 1 天-1。无需检查价值和使用abs方法。
  • 不要使用 JVM 默认时区:而不是ZoneId.systemDefault(),使用timezone你已经拥有的(你在setDefault方法中使用的那个)
  • instant.atZone相当于ZonedDateTime.ofInstant。IMO,atZone更具“可读性”,但在这种情况下,这是选择和代码风格的问题。对最终结果没有影响。

有了这个,你可以这样做:

// call directly, no need to change the default timezone
System.out.println(addDays(1459123200, -1, "Europe/Stockholm"));

这将打印:

2016-03-27T03:00+02:00[欧洲/斯德哥尔摩]

于 2017-09-11T13:34:59.227 回答
1

我想我可以回答我上面的问题。

这是代码。

public ZonedDateTime addDays(long myUTCTimeInSeconds, int days) {
    Instant instant = Instant.ofEpochSecond(myUTCTimeInSeconds);
    ZonedDateTime dateTimeWithOffSet = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
    if (localDays >= 0) {
        dateTimeWithOffSet = dateTimeWithOffSet.plusDays(localDays);
    } else {
        dateTimeWithOffSet = dateTimeWithOffSet.minusDays(abs(localDays));
    }
    return dateTimeWithOffSet;
}

如果时区与系统时区不同,我们可以设置默认时区,并在调用上述方法后将时区重置为:

TimeZone systemDefaultTimeZone = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone(timezone));

addDays(1459123200, 1);
TimeZone.setDefault(systemDefaultTimeZone);
于 2017-03-07T05:41:47.813 回答