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

2022-08-31 12:54:21

我正在为一些方便的方法编写一些测试用例,我正在更新这些方法,并决定看看如果我在第0年使用的方法会发生什么。据我所知,0年实际上从未存在过:公元1年之前的一年是公元前1年。(这是基于我多年前读到的一篇文章,我早就忘记了它的来源。令我惊讶的是,我的测试表明0年是闰年!LocalDateisLeapYear()

我意识到该类实现了ISO-8601,但ISO-8601真的表明0年存在吗?我不愿意相信测试的人会错过这个测试用例,但我也不愿意相信像ISO-8601这样的国际标准会犯这样一个明显的错误。java.time.LocalDateLocalDate

另一种可能性是,我读到的文章是完全错误的。(或者它当时是正确的,但后来被重新考虑。

这并不是很重要,但我很好奇错误在哪里:JAVA的类ISO-8601,或者我对时间计算方式的理解。LocalDate


答案 1

TL;DR:正在按照国际标准(ISO 8601)执行其记录要执行的操作。这是否“正确”是一个完全不同的问题。LocalDate

LocalDate Javadoc 本身包含以下警告:

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

维基百科有更多关于历的信息。除此之外,它还说:

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

请原谅我,当我为这一切偏离一些历史背景时。

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

然而,在第一世纪,没有人以这种方式计算年份;相比之下,路加福音将耶稣开始事奉的那一年描述为

在提比略·凯撒统治的第十五年,本丢·彼拉多是犹太的总督,希律是加利利的四位一体,他的兄弟腓力四世是伊图赖亚和特拉霍尼蒂斯地区的腓力四十四世,利萨尼亚斯是阿比林的四位一体,

表面上看,这应该是公元30年,因为路加福音形容耶稣当时“大约三十岁”。但现代历史学家普遍认为,狄奥尼修斯·埃克西古斯(Dionysius Exiguus)在公元525年提出了anno domini系统,他弄错了,因此年份的编号至少相差一两年。(确切的日期仍然有些争议;如果你关心更多细节,请参阅维基百科

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

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


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


答案 2

来自维基百科

...在天文年份编号(与公元前1年的儒略年重合)和ISO 8601:2004(与公元前1年的公历年重合)中有一个零年。


推荐