LocalDate
仅处理预测公历。从它的javadoc:
ISO-8601 日历系统是当今世界大部分地区使用的现代民用日历系统。它相当于预测的公历系统,在该系统中,今天的闰年规则适用于所有时间。对于当今编写的大多数应用程序,ISO-8601 规则完全适用。但是,任何使用历史日期并要求它们准确的应用程序都会发现 ISO-8601 方法不适合。
相比之下,旧java.util.GregorianCalendar
类(也间接用于 toString() 的输出java.util.Date
)使用可配置的公历截止日期,默认为 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); // -14830974000000
System.out.println(tCutOver); // default gregorian cut off day in "epoch millis"
System.out.println((tCutOver - t1500) / 1000); // output: 2611699200 = 30228 * 86400
应该注意的是,由于 和 之间的时区偏移差异,-12219292800000L
您之前评论中提到的值与 5 小时不同。所以在 EST 时区(美国/纽约)我们正好有 30228 天的差异。对于所讨论的时间跨度,我们应用儒略历规则,即每四年为闰年。tCutOver
America/New_York
UTC
在 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 的跳转。所以对我来说,你的问题是“我如何告诉日期对象将 ms 返回到正确的公历日期?” 已经回答 - 无需更正。请记住,这种复杂的东西在生产中使用了相当长的时间,并且可以预期在这么多年后正常工作。
如果您真的想将 JSR-310 用于这些东西,我重申不支持公历截止日期。最好的事情是您可以自己解决问题。
例如,您可能会考虑外部库Threeten-Extra,其中包含自 0.9 版以来的预测儒略历。但是,处理旧儒略历和新公历之间的转换仍将是您的努力。(并且由于新年开始等许多其他原因,不要期望此类库能够处理真实的历史日期。)
2017 年更新:另一个更强大的选择是使用我的库Time4J的HistoricCalendar ,它处理的不仅仅是 julian/gregorian-cutover。