为什么解析的时间戳为-923130000和-923130001的LocalDateTime变量之间的秒数为3599?

问题描述

由于LocalDateTime失败,Java解析时间戳-923130000和-923130001。两次结果之间的秒数是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版本:

$ 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上执行。

解决方法

显然是时区数据中的错误

Java 8和Java 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安装中的时区数据库。参见Timezone Updater Tool

当天的提示:始终比ZonedDateTime更喜欢LocalDateTimeZonedDateTime知道自己的时区和偏移量。在您的情况下,只需打印ZonedDateTime对象或在调试器中检查它们即可发现正在发生的事情。将时区作为日期时间对象的一部分可以防止许多愚蠢的错误。 ZonedDateTime可以采用LocalDateTime可以(甚至更多)进行格式化的方式,因此向用户显示的内容不变。

链接: Time Changes in Shanghai Over the Years

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...