LocalDate
仅处理普通公历日历。从其javadoc:
ISO-8601日历系统是当今世界上使用的现代公民日历系统。它相当于普通公历日历系统,在其中适用于所有时间的闰年规则。对于今天编写的大多数应用程序,ISO-8601规则完全合适。但是,任何利用历史日期并要求它们准确的应用程序都会发现ISO-8601方法不适用。
相比之下,旧的java.util.GregorianCalendar
类(也间接用于java.util.Date
的toString()-输出)使用可配置的格里高利分界线,默认为1582-10-15,作为儒略和格里高利日历规则之间的分离日期。
因此,LocalDate
不能用于任何类型的历史日期。
请注意,即使是
java.util.GregorianCalendar
在正确配置区域依赖的截止日期时也经常失败。例如,在1752年之前,英国在3月25日开始新的一年。而且许多国家还有更多的历史偏差。在欧洲以外,甚至在引入格里高利历之前,朱利安历也无法使用(或者只能从殖民主义者的角度最好地使用)。
更新:由于评论中的问题:
为了解释值
-14830974000000
,让我们考虑以下代码及其输出:
SimpleDateFormat format = new SimpleDateFormat("MMddyyyy", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
Date d = format.parse("01011500");
long t1500 = d.getTime();
long tCutOver = format.parse("10151582").getTime();
System.out.println(t1500);
System.out.println(tCutOver);
System.out.println((tCutOver - t1500) / 1000); // output: 2611699200 = 30228 * 86400
请注意,你之前评论中提到的值
-12219292800000L
由于
America/New_York
和
UTC
之间的时区偏差不同,与
tCutOver
相差5个小时。因此,在EST时区(美国/纽约),我们有确切的30228天差异。对于所讨论的时间跨度,我们应用儒略历规则,即每四年为闰年。
在1500年至1582年期间,我们有82 * 365天+21个闰日。然后我们还需要在1582-01-01和1582-10-01之间添加273天,最后再加上4天直到切换(记住10月4日后面是10月15日)。总共:82 * 365 + 21 + 273 + 4 = 30228(需要证明的内容)。
请解释一下,为什么你期望的时间值与 -14830974000000 毫秒不同。
对我来说看起来是正确的,因为它处理了您系统的时区偏移、1582年之前的儒略历规则以及从1582年10月4日跳转到切换日期1582-10-15。所以对于我来说,你的问题“如何告诉日期对象将毫秒返回到正确的公历日期?”已经得到了回答——无需更正。请记住,这些复杂的内容在生产中使用了相当长的时间,并且可以预期在这么多年后能够正确地工作。
如果你真的想要使用JSR-310来处理这些内容,我要重申,它没有支持公历改革日期的功能。最好的方法是你自己做一个解决方案。
例如,你可以考虑使用外部库Threeten-Extra,它自0.9版本开始包含一个追溯儒略历的日历。但是你仍然需要努力处理旧儒略历和新公历之间的转换。(并且不要指望这样的库能够处理真实的历史日期,因为还有许多其他原因,比如新年的开始等等。)
2017年更新: 另一个更强大的选项是使用Time4J库中的HistoricCalendar,它可以处理比仅仅儒略/格里历转换更多的内容。
gregorianCutoff
字段的注释:“默认值为 1582 年 10 月 15 日(公历)00:00:00 UTC 或 -12219292800000L。对于此值,1582 年 10 月 4 日(儒略历)之后是 1582 年 10 月 15 日(公历)。” - Rick Hanlon II