为什么使用Instant将1582之前的Java日期转换为LocalDate会给出不同的日期?
考虑此代码:
Date date = new SimpleDateFormat("MMddyyyy").parse("01011500");
LocalDate localDateRight = LocalDate.parse(formatter.format(date), dateFormatter);
LocalDate localDateWrong = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate();
System.out.println(date); // Wed Jan 01 00:00:00 EST 1500
System.out.println(localDateRight); // 1500-01-01
System.out.println(localDateWrong); // 1500-01-10
我知道1582年是儒略历和格里高利历的分界点。我不知道为什么会发生这种情况,或者如何适应它
以下是我到目前为止得出的结论:
- 日期对象的
BaseCalender
设置为JulianCalendar
date.toInstant()
只返回Instant.ofEpochMilli(getTime())
date.getTime()
返回-1483097400000- -1483097400000是星期三,1月10日下午5:00:00 GMT格里高利
所以看起来getTime()
返回的毫秒要么是错误的(不太可能),要么只是与我预期的不同,我需要解释差异
# 1 楼答案
LocalDate
只处理公历前的。从它的javadoc相比之下,旧的
java.util.GregorianCalendar
类(在java.util.Date
的toString()输出中也间接使用)使用了一个可配置的公历截止日期,默认为1582-10-15,作为朱利安和公历规则之间的分离日期所以
LocalDate
不能用于任何历史日期但请记住,即使配置了依赖于区域的正确的截止日期,即使
java.util.GregorianCalendar
也经常失败。例如,英国在1752年之前的3月25日开始了这一年。许多国家还存在更多的历史偏差。在引入公历之前,欧洲以外甚至连儒略历都不可用(或者只能从殖民主义的角度使用)由于评论中的问题而更新:
< >解释值{{CD6>},让我们考虑下面的代码及其输出:需要注意的是,由于
America/New_York
和UTC
之间的时区偏移差异,您之前的评论中提到的-12219292800000L
值与tCutOver
值相差5小时。所以在美国东部时区(美国/纽约),我们正好有30228天的差异。对于所讨论的时间跨度,我们应用朱利安历法的规则,即每四年是闰年在1500到1582之间,我们有82*365天+21闰日。然后我们还要在1582-01-01和1582-10-01之间增加273天,最后是4天,直到切换(记住10月4日之后是10月15日)。总计:82*365+21+273+4=30228(有待证明)
请向我解释为什么您期望的值不同于-1483097400000毫秒。这对我来说似乎是正确的,因为它处理了系统的时区偏移、1582年之前的儒略历规则以及从1582年10月4日跳到1582-10-15日那么对于我来说,你的问题是“我如何告诉date对象将ms返回到正确的公历日期?”已得到回答-无需更正。请记住,这个复杂的东西在生产使用中需要相当长的时间,并且可以在这么多年后正常工作
如果你真的想用JSR-310来做这件事,我重复一遍,格雷戈里的转换日期是不受支持的。最好的事情是,你可以做自己的工作
例如,您可以考虑外部库{A2},它包含从发布0.9起的一个前置朱利安日历。但是,处理旧儒略历和新公历之间的转换仍然是你的努力。(由于新年开始等许多其他原因,不要指望这样的图书馆能够处理真正的历史日期。)
2017年更新:另一个更强大的选项是使用我的库HistoricCalendar中的Time4J,它处理的不仅仅是julian/gregorian切换