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

2023-12-14

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

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

这是一个示例:

    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

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


差异在于如何实施Date and Instant它们的实现相互交互,Date 使用公历/儒略历,Instant 使用 ISO 标准的日期,在儒略历切换之前遵循修改后的公历。

The GregorianCalendar 执行有一个特别说明:

在公历转换之前,GregorianCalendar 实现儒略历。公历和儒略历之间的唯一区别是闰年规则。儒略历每四年指定一次闰年,而公历则省略了不能被 400 整除的世纪年。

嗯,是的,从技术上来说。但对于这个问题,我们不quite遇到这个。

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

正如预期的那样,得到的日期是 1582 年 10 月 4 日。

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

这会产生一个日期,十月15, 1582.

蝙蝠侠,这是什么魔法?

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

然而,今年见证了公历转换的开始,当时被称为“Inter gravissimas”的教皇敕令引入了公历,从一开始就被西班牙、葡萄牙、波兰立陶宛联邦和当今意大利的大部分地区采用。在这些国家,这一年继续正常进行,直到10 月 4 日,星期四。然而,第二天变成了 10 月 15 日星期五(就像平年从星期五开始一样),

From 维基百科上的 1582

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

日期:1582 年 10 月 4 日 00:00:00

即时:1582-10-14T00:00:00Z

这里有 10 天的间隔,并且该时刻存在于“技术上不存在的日期”的原因由以下定义解释:ISO 即时日期.

该标准规定每个日期必须是连续的,因此使用儒略历将违反标准(因为在切换日期,日期不会连续)。

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

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

如果你是显示历史事件日期,您最好使用Date or JulianCalendarDateFormatter 显示正确正确的历史日期,就像历史上实际发生的那样。打印出历史时期的 ISO 时间可能显得无意义或不准确,但以此格式存储时间仍然有效。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java.util.Date 和 java.time.Instant 之间转换古代日期时出现差异 的相关文章

随机推荐