0

Java 将时间戳 -923130000 和 -923130001 解析为 LocalDateTime 失败。两个结果之间的秒数是3599,太诡异了。

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;

public class TestLocalDateTime {

    public static void main(String[] args) {
        System.out.println("-923130000: " + toLocalDateTime(-923130000L));
        System.out.println("-923130001: " + toLocalDateTime(-923130001L));

        System.out.println(ChronoUnit.SECONDS.between(toLocalDateTime(-923130000L), toLocalDateTime(-923130001L)));
    }

    private static LocalDateTime toLocalDateTime(Long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
    }

}

输出:

-923130000: 1940-09-30T23:00
-923130001: 1940-09-30T23:59:59
3599

爪哇版:

$ java -version
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

代码在 macOS 上执行。

4

1 回答 1

5

显然时区数据中的错误

Java 8 和 9 似乎认为中国时区在 1940 年 9 月 30 日之后的午夜从偏移 +09:00 变为 +08:00,因此 23:59:59 之后的第二个将再次是 23:00。显示这一点的时区包括亚洲/重庆、亚洲/上海、亚洲/重庆、中国和亚洲/哈尔滨。

在这一点上,Java 似乎也是错误的。我在dateandtime.com上查看了上海,它知道今晚没有时区转换。我也无法在 Java 11 上重现相同的行为。

查看这一点的一种方法是使用以下代码片段:

    ZoneId zone = ZoneId.of("Asia/Shanghai");
    System.out.println(Instant.ofEpochSecond(-923_130_001L).atZone(zone));
    System.out.println(Instant.ofEpochSecond(-923_130_000L).atZone(zone));

Java 8 和 9 上的输出:

1940-09-30T23:59:59+09:00[Asia/Shanghai]
1940-09-30T23:00+08:00[Asia/Shanghai]

Java 11 上的输出:

1940-09-30T23:59:59+09:00[Asia/Shanghai]
1940-10-01T00:00+09:00[Asia/Shanghai]

假设您不想立即升级到 java 10 或 11 或更高版本,您可以做的最好的事情可能是更新当前 Java 8 安装中的时区数据库。请参阅时区更新工具

每日提示:总是更ZonedDateTime喜欢LocalDateTime. AZonedDateTime知道自己的时区和偏移量。在您的情况下,只需打印ZonedDateTime对象或在调试器中检查它们就会揭示正在发生的事情。将时区作为日期时间对象的一部分可以防止许多愚蠢的错误。AZonedDateTime可以以任何方式格式化 a LocalDateTimecan(以及更多),因此向用户呈现的内容不变。

链接: 历年上海时间变迁

于 2020-10-16T11:32:28.703 回答