为了账号安全,请及时绑定邮箱和手机立即绑定

Java 说第 0 年是闰年,但第 0 年从未存在过

Java 说第 0 年是闰年,但第 0 年从未存在过

慕丝7291255 2021-12-01 15:27:31
我正在为一些我正在更新的便捷方法编写一些测试用例,并决定看看如果我在 0 年使用LocalDate'sisLeapYear()方法会发生什么。据我所知,0 年实际上从未存在过:公元 1 年之前的一年是 1公元前。(这是基于我多年前读过的一篇文章,我早已忘记了它的来源。)令我惊讶的是,我的测试表明 0 年是闰年!我意识到java.time.LocalDate该类实现了 ISO-8601 但 ISO-8601 真的表明 0 年存在吗?我不愿意相信进行测试的人LocalDate会错过这个作为测试用例的人,但我也不愿意相信像 ISO-8601 这样的国际标准会犯如此明显的错误。另一种可能性是我阅读的文章完全错误。(或者当时是正确的,但后来被重新考虑。)这不是很重要,但我很想知道错误在哪里:ISO-8601、Java 的LocalDate类,或者我对时间计算方式的理解。
查看完整描述

2 回答

?
catspeake

TA贡献1111条经验 获得超0个赞

LocalDate正在按照国际标准 (ISO 8601) 做记录在案的事情。这是否“正确”是一个完全不同的问题。

LocalDateJavadoc中本身就包含这个警告:

它相当于预兆公历系统,其中今天的闰年规则适用于所有时间。对于当今编写的大多数应用程序,ISO-8601 规则完全适用。但是,任何使用历史日期并要求它们准确的应用程序都会发现 ISO-8601 方法不合适。

维基百科有更多关于公历的信息。除其他外,它说:

在数学上,为了便于计算负 (BC) 年和正 (AD) 年之间的年数,将更早的年份表示为负数会更方便。这是天文年编号和国际标准日期系统 ISO 8601 中使用的约定。在这些系统中,0 年是闰年。

请原谅我,因为这一切,我会离题到一些历史背景。

西方历法中的年份表面上是从耶稣基督的诞生开始计算的,但这样做的想法始于 6 世纪,而我们目前的日历是基于 16 世纪的计算。由于罗马数字既不代表零也不代表负数,因此年份要么被计算为“耶稣之后”(AD,表示anno domini),要么“耶稣之前”(BC,表示“基督之前”)。因此,传统上,公元前 1 年之后是公元 1 年,中间没有零年。

然而,在第一世纪,没有人这样计算年数。相比之下,路加福音将耶稣开始传道的那一年描述为

凯撒提比略十五年,本丢彼拉多为犹地亚的总督,希律为加利利的分封王,他的兄弟腓力分封为伊图雷亚和特拉科尼蒂斯地区的分封王,吕萨尼亚为亚比林的分封王,

表面上这应该是公元 30 年,因为路加描述耶稣当时“大约三十岁”。但现代历史学家普遍认为,公元 525 年提出anno domini系统的Dionysius Exiguus错了,因此年数至少相差一两年。(确切日期仍然有些争议;如果您想了解更多细节,请参阅维基百科。)

但现在修复已经太晚了;即使是从儒略历到格里高利历的过渡,相差不到两周,也遇到了广泛的政治阻力,因为这种转变在整个欧洲发生了几个世纪——你可以想象年份编号的变化是多么具有破坏性将是现在!

那么这段历史与今天的软件有什么关系呢?不幸的是,由于历史上计算和记录日期的方式多种多样,您要么需要在时间前后移动时以一致的方式放弃日历,要么必须放弃计算出的日期与真实的人当时会使用的日期有任何对应关系。分歧发生的速度比你想象的要快:不到 100 年前,许多欧洲国家仍在使用儒略历,与欧洲其他国家相差近两周!


可以理解的是,LocalDate洗掉这个烂摊子,只按照我们今天使用的方式来实现日历。重申 Javadoc 所说的:“对于今天编写的大多数应用程序,ISO-8601 规则完全合适。但是,任何利用历史日期并要求它们准确的应用程序都会发现 ISO-8601 方法不合适。”


查看完整回答
反对 回复 2021-12-01
?
慕容森

TA贡献1853条经验 获得超18个赞

来自维基百科

...天文年编号(与公元前 1 年的儒略年一致)和 ISO 8601:2004(与公元前 1 年的格里高利年一致)有一个零年


查看完整回答
反对 回复 2021-12-01
  • 2 回答
  • 0 关注
  • 295 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信