这是joda time中的错误吗?处理非常古老(0000 年)的即时/负纪元

Posted

技术标签:

【中文标题】这是joda time中的错误吗?处理非常古老(0000 年)的即时/负纪元【英文标题】:Is this a bug in joda time? Handling very old (year 0000) instant / negative epoch 【发布时间】:2021-12-02 02:26:07 【问题描述】:

当我们从带有年份0001java.util.Date 构造它时,似乎DateTime 没有用正确的日期初始化它自己。

import java.time.LocalDateTime;
import java.util.TimeZone;
public class TestMain 
    public static void main(String[] args) 
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        java.util.Date d = new java.util.Date(-62135640000000L);
        java.time.Instant i = java.time.Instant.ofEpochMilli(-62135640000000L);
        System.out.println("d = new java.util.Date(-62135640000000L)                      : " + new java.util.Date(-62135640000000L));
        System.out.println("new org.joda.time.DateTime(d)                                 : " + new org.joda.time.DateTime(d));
        System.out.println("new org.joda.time.DateTime(-62135640000000L)                  : " + new org.joda.time.DateTime(-62135640000000L));
        System.out.println("java.time.LocalDateTime.ofInstant(i, java.time.ZoneOffset.UTC): " + LocalDateTime.ofInstant(i, java.time.ZoneOffset.UTC));
    

输出:

d = new java.util.Date(-62135640000000L)                      : Sun Jan 02 12:00:00 UTC 1
new org.joda.time.DateTime(d)                                 : 0000-12-31T12:00:00.000Z
new org.joda.time.DateTime(-62135640000000L)                  : 0000-12-31T12:00:00.000Z
java.time.LocalDateTime.ofInstant(i, java.time.ZoneOffset.UTC): 0000-12-31T12:00

除了时区相关的差异,如果你注意:

日期是02 in Date object 和 31 in DateTime(或00,如果您更改为UTC) 年份是0001 in Date object 和 0000 in DateTime

是我做错了什么,还是这是一个错误?

做了更多的计算

62135640000000 / 1000 / 3600 / 24 / 365.25 = 1968.9596167008898015058179329227
0.9596167008898015058179329227 * 365.25 = 350.5
365.25 - 350.5 = 14.75

所以-62135640000000 = 负 1969 年零 350.5 天。或 0000 年开始后约 14.75 天。

【问题讨论】:

一年不是 365.0000 天。 @VGR,你是对的。更新。还添加了java.time 行为。 【参考方案1】:

不是错误:儒略历与预测公历

这不是错误。它是有意识地设计的。这里有两种不同的日历系统:

    过时的 java.util.Date 类使用儒略历来表示 1582 年之前的日期。它试图反映当时欧洲大部分地区实际使用的日历系统。 默认情况下,Joda-Time 和 java.time 都使用 ISO 8601 日历系统(如果您明确指定其他日历系统,则支持它们)。 ISO 8601 反过来使用预测公历。 Proleptic Gregorian calendar 是通过将 Gregorian calendar 的规则外推到 Gregorian calendar 发明和引入之前的时代而创建的。因此,它给出的日期与当时实际使用的日期不一致,但反过来,定义更明确。

这两个日历在大多数日期中相隔几天,当我们接近 1582 年或更晚的朱利安-格里高利交叉时,最长可能会相隔几周,具体取决于司法管辖区。

Joda-Time 支持公历/儒略历

Joda-TIme 也通过 GJChronology 类支持 Date 使用的联合公历/朱安历系统。

    DateTime dt = new DateTime(-62_135_640_000_000L,
            GJChronology.getInstanceUTC());
    System.out.println("DateTime with GJChronology: " + dt);

输出:

GJChronology 的日期时间:0001-01-02T12:00:00.000Z

年、月、日都与您从Date 得到的一致。

链接

ISO8601 Java calendar system 在 Joda-Time 网站上。 Wikipedia article: ISO 8601 ***上的Proleptic Gregorian calendar 类似问题:Java: How to get the timestamp of '1000-01-01 00:00:00' in UTC? 不同之处在于该问题是关于来自 java.time 的 ZonedDateTime,而不是关于 Joda-Time。

【讨论】:

以上是关于这是joda time中的错误吗?处理非常古老(0000 年)的即时/负纪元的主要内容,如果未能解决你的问题,请参考以下文章

JAVA秒会技术之Joda-Time满足你所有关于日期的处理

我应该用threeten代替joda-time吗

Joda Time 使用

joda-time的使用,创建时间处理工具类DateTimeUtil

HSQLDB + EclipseLink + 生成 DDL + DATE JODA TIME = 错误的 TIMESTAMP

参数类型的隐式 ParameterBinderFactory[org.joda.time.LocalDateTime]