java - 在 java.util.Date 和 java.time.Instant 之间转换古代日期时出现差异

标签 java date java-8

我有使用 java.util.Date 创建一个古老日期(0002 年 11 月 30 日)的遗留代码。我正在尝试更新我能更新的代码,但这需要在 Date 和 LocalDate 等之间进行转换。我无法完全摆脱对 Date 或古老日期选择的使用。

我发现在使用这个古老的日期在 Date 和 Instant 之间来回转换时似乎出现了错误,并希望有人能解释发生了什么。

这是一个示例:

    Date date = new Date();
    Instant instant = date.toInstant();
    System.out.println("Current:");
    System.out.println("Date: "+date);
    System.out.println("Instant: "+instant);
    System.out.println("Date epoch:    "+date.getTime());
    System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);

    System.out.println("\nAncient from Date:");
    Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("MST"));
    cal.set(2, Calendar.NOVEMBER, 30, 0, 0, 0);
    date = cal.getTime();
    instant = date.toInstant();
    System.out.println("Date: "+date);
    System.out.println("Instant: "+instant);
    System.out.println("Date epoch:    "+date.getTime());
    System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);

    System.out.println("\nAncient from Instant:");
    instant = Instant.parse("0002-11-30T00:00:00Z");
    date = Date.from(instant);
    System.out.println("Date: "+date);
    System.out.println("Instant: "+instant);
    System.out.println("Date epoch:    "+date.getTime());
    System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);

打印以下内容:

Current:
Date: Tue Sep 18 12:34:27 MST 2018
Instant: 2018-09-18T19:34:27.177Z
Date epoch:    1537299267177
Instant epoch: 1537299267000

Ancient from Date:
Date: Thu Nov 30 00:00:00 MST 2
Instant: 0002-11-28T07:00:00.247Z
Date epoch:    -62075437199753
Instant epoch: -62075437200000

Ancient from Instant:
Date: Fri Dec 01 17:00:00 MST 2
Instant: 0002-11-30T00:00:00Z
Date epoch:    -62075289600000
Instant epoch: -62075289600000

因此,如果我在 2 日 11 月 30 日创建一个 Instant,然后转换为日期,则日期为 2 日 12 月 1 日。如果我从 2 日 11 月 30 日的日期开始,则 Instant 为 2 日 11 月 28 日。我知道Date 和 Instant 都不存储时区信息,但为什么根据我是从 Date 还是 Instant 开始,纪元如此不同?无论如何我可以解决这个问题吗?我需要能够从 Date 或 Instant 开始,并以相同的纪元值结束。如果知道为什么默认的 toString() 在给定相同纪元的情况下会显示如此不同的日期,那就太好了。

最佳答案

差异在于 DateInstant 的实现如何就其实现相互交互,Date 使用 Gregorian/Julian 日历,Instant 使用 ISO 标准对于 Date,在 Julian 日历转换之前遵循修改后的 Gregorian 日历。

公历 implementation有特别说明:

Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.

嗯,是的,从技术上讲。但是对于这个问题,我们并不遇到这种情况。

cal.set(1582, Calendar.OCTOBER, 4, 0, 0, 0);

如预期的那样,这会产生一个日期,即 1582 年 10 月 4 日。

cal.set(1582, Calendar.OCTOBER, 5, 0, 0, 0);

这会产生一个日期,即 1582 年 10 月 15

这是什么魔法, bat 侠?

好吧,这不是编码错误,它实际上是 GregorianCalendar 的实现。

However, this year saw the beginning of the Gregorian Calendar switch, when the Papal bull known as Inter gravissimas introduced the Gregorian calendar, adopted by Spain, Portugal, the Polish–Lithuanian Commonwealth and most of present-day Italy from the start. In these countries, the year continued as normal until Thursday, October 4. However, the next day became Friday, October 15 (like a common year starting on Friday),

来自 Wikipedia on 1582

当我们检查 1582 年 10 月 4 日时,会发生以下情况:

Date: 1582-Oct-04 00:00:00

Instant: 1582-10-14T00:00:00Z

这里有 10 天的间隔,并且瞬间存在于“技术上不存在的日期”的原因由 ISO instant dates 的定义解释。 .

The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).

SO,虽然 1582 年 10 月 14 日在现实中从未存在过,但根据定义,它存在于 ISO 时间中,但根据儒略历,它发生在现实世界的 1582 年 10 月 4 日。

由于我假设第一段有额外的闰年漂移,其中儒略世纪 1500、1400、1300、1100、1000、900、700、600、500、300、200、100 有额外的闰日未计算在内因为在公历中,我们慢慢地从 +10 偏移回 -1。这可以通过以 +100 为增量调整年份来验证。

如果您要显示历史事件日期,最好使用DateJulianCalendar DateFormatter 来显示正确的历史日期,因为它确实发生在历史上。打印出历史时期的 ISO 时间可能显得荒谬或不准确,但以这种格式存储时间仍然有效。

关于java - 在 java.util.Date 和 java.time.Instant 之间转换古代日期时出现差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53382928/

相关文章:

java - .stream() 和 Stream.of 有什么区别?

java - 数组、 double 、IF/Else

java - 使用日期和日历

postgresql - 从 PostgreSQL 中的时间戳获取日期

Java 8 方法引用多个不同的构造函数

java - 如何确定各种Java 8堆内存名称?

Java 无法将十六进制字符串解析为 int

java - junit 理论解析为 ParameterizedAssertionError 而不是失败

python - 如何使用 python 找出客户契约(Contract)终止前的账单日期?

javascript - 在我的日期验证中合并前导零