我正在为一些正在更新的便捷方法编写一些测试用例,并决定看看如果在0年使用LocalDate
的isLeapYear()
方法会发生什么。据我所知,0年实际上不存在:1 AD之前的一年是公元前1年。 (这是基于我多年以前读过的一篇文章,该文章我早就忘记了。)令我惊讶的是,我的测试表明0年是a年!
我意识到java.time.LocalDate
类实现了ISO-8601,但是ISO-8601确实表明存在0年吗?我不愿意相信测试LocalDate
的人会错过此作为测试用例,但是我也不愿意相信像ISO-8601这样的国际标准会犯这样一个明显的错误。
另一种可能性是我阅读的文章完全是错误的。 (或者那是正确的,但后来又重新考虑了。)
这不是很重要,但是我很想知道错误在哪里:ISO-8601,Java的LocalDate
类,或者我对时间的理解。
最佳答案
TL; DR:LocalDate
正在按照国际标准(ISO 8601)进行记录的工作。这是否“正确”是一个完全不同的问题。
LocalDate
Javadoc本身包括以下警告:
Wikipedia拥有有关proleptic Gregorian calendar的更多信息。其中包括:
请原谅我一会儿,以便我能谈谈所有这些历史背景。
表面上的历法从表面上看是从耶稣基督的出生开始算起的,但是这样做的想法始于六世纪,而我们目前的历法是基于十六世纪的计算得出的。由于罗马数字既不表示零也不表示负数,因此年份被计为“在耶稣之后”(公元,对于anno domini)或“在耶稣之前”(BC,对于“在基督之前”)。因此,按照传统,公元前1个后接公元1个,之间没有零年。
但是,在第一世纪,没有人以这种方式计算年份。为了比较,路加福音将耶稣开始传道的那年描述为
表面上看,这本来应该是公元30年,因为卢克当时将耶稣描述为“大约三十岁”。但是现代历史学家普遍认为,狄奥尼修斯·埃希古斯(Dionysius Exiguus)在公元525年提出了anno domini系统,但它弄错了,因此年份的编号至少要间隔一到两年。 (确切的日期还是有争议的;如果您想了解更多详细信息,请参见Wikipedia。)
但是现在修复为时已晚。甚至从朱利安历法到格里高利历的转换(相差不到两周)也遇到了广泛的政治阻力,因为整个欧洲的转换历时数个世纪-您可以想像年号变更的破坏性会是现在!
那么,这段历史与今天的软件有什么关系?不幸的是,由于在整个历史中计算和记录日期的方式多种多样,因此您要么在时间向前和向后移动时以一致的方式放弃日历,要么必须放弃计算的日期与真实人当时使用的日期有任何对应关系。差异发生的速度比您想象的要快:不到100年前,许多欧洲国家仍在使用儒略历,与欧洲其他国家相差将近两个星期!
可以理解的是,LocalDate
会洗手间,只用我们今天使用它的方式来实现日历。重申Javadoc所说的话:“对于今天编写的大多数应用程序,ISO-8601规则是完全合适的。但是,任何使用历史日期并要求它们准确的应用程序都会发现ISO-8601方法不合适。”