如何验证农历计算
参考日期
农历日期换算、节气时刻、历书分类和界面行为,应分别验证。其中一项相符,并不能证明其他各项也正确。一组有用的检查应同时涵盖月界、年界和月内日期。
选择一个独立的参考来源,明确其历法约定和覆盖范围。使用同一计算引擎的另一个网站,可能会重复同样的错误。将参考资料的版本与预期数值一并记录,以便日后追溯变化。
本站支持公元1年至2100年的民用日期。锁定版本的计算引擎在1582-10-04及以前采用儒略历民用日期,之后接续格里历1582-10-15。这套民用日期序列中没有10月5日至10月14日。若比较采用向实施之前的年代延伸格里历规则的历法,即逆推格里历,那么所检验的早期日期对应关系就不同。
这一约定说明的是软件的民用日期标签,并不证明中国历史上使用了哪种历法。应测试支持范围的两个端点,以及超出范围日期的处理方式。民用日期范围也不同于完整农历年的范围,两者的起止日并不相同。
每项结果都应存储完整的民用日期及历法约定、农历年、农历月序数、闰月标志和农历日。应区分月份编号与其在年内的先后位置:闰六月按时间顺序是第七个月,但月序数仍为六。
测试用例
精确日期检查
以下日期涵盖春节、有效的公历闰日,以及非闰月和闰月的两端。本表以农历年开始时所在的公历年份标记农历年份。“非闰月”表示闰月标志为假。
| 公历日期 | 农历年份 | 月 | 类型 | 农历日 |
|---|---|---|---|---|
| 2024-02-09 | 2023 | 12 | 非闰月 | 30 |
| 2024-02-10 | 2024 | 1 | 非闰月 | 1 |
| 2024-02-29 | 2024 | 1 | 非闰月 | 20 |
| 2025-07-24 | 2025 | 6 | 非闰月 | 30 |
| 2025-07-25 | 2025 | 6 | 闰月 | 1 |
| 2025-08-22 | 2025 | 6 | 闰月 | 29 |
| 2025-08-23 | 2025 | 7 | 非闰月 | 1 |
| 2033-12-21 | 2033 | 11 | 非闰月 | 30 |
| 2033-12-22 | 2033 | 11 | 闰月 | 1 |
| 2034-01-19 | 2033 | 11 | 闰月 | 29 |
| 2034-01-20 | 2033 | 12 | 非闰月 | 1 |
| 2034-02-19 | 2034 | 1 | 非闰月 | 1 |
每个日期都应进行双向换算。公历转农历应输出全部四项农历字段,农历转公历则应还原表列日期。随后,应测试分界前后的完整日期序列,而不只测试首日。这样可以区分月初计算错误与显示标签遗漏闰月标志这两种问题。
仅靠往返换算不能证明准确性。两个函数可能共用同一张错误表,仍能完全互相还原。与独立的预期数值比较,是另一项检查。穷尽式比较应记录比较了多少个日期、使用了什么参考来源,以及每一处不一致。
结构与输入检查
| 检查 | 预期行为 |
|---|---|
| 从一个农历月的最后一天向后推进一天 | 到达时间顺序上下一个月的初一,月序数、闰月标志和农历年份均正确 |
| 从非闰月进入随后同名的闰月 | 沿用月序数,将闰月标志改为真 |
| 从闰月进入下一个月 | 清除闰月标志,递增月序数,并在需要时跨入下一年 |
| 请求2025年仅有29天的闰六月的三十日 | 拒绝这个不存在的农历日期 |
| 请求某年并不存在的闰月 | 拒绝请求,而不是用同名的非闰月替代 |
| 先输入2000年2月29日,再输入2100年2月29日 | 接受第一个公历日期,拒绝第二个 |
| 按本站的儒略历约定输入1500年2月29日 | 将其作为有效的儒略历日期接受 |
| 按本站的历法切换约定,从1582-10-04向后推进一个民用日 | 到达1582-10-15,恰好经过一天 |
| 将有效日期转为农历,再转回原历法 | 还原原日期,不丢失闰月身份 |
儒略历每四年增加一个闰日。格里历规则将世纪年排除在闰年之外,只有能被400整除的世纪年例外。因此,闰日测试必须注明使用哪一种民用历法。
上述拒绝输入的检查针对严格的日期输入界面。底层库也可能提供有文档说明的规范化处理,例如将超出范围的日数顺延到下个月。应分别测试这些行为,不要把规范化后的值误当作原始输入。
界面检查
语言切换、浏览器刷新、月份导航和黄历入口,应与换算函数分开测试。切换语言应保留所选日期和当前显示月份。浏览其他月份应保留已选日期,直到用户另选一天。应检查黄历入口是否打开设备本地的公历日期,以及固定日期页面在其他时区是否仍保留写明的民用日期。
应纳入一个设备本地日期与历法参考日期不同的测试时刻。这样可以发现两类错误:用天文参考时间选择黄历日期,或用浏览器时间重建农历月界。
节气与分界
比较节气时,需要节气名称、民用日期、时刻、时间标准和公布精度。应先把两个数值统一到相同的民用历法和时间标准,再作比较。公布到分钟的时刻,不能证明精确到秒也相符。
归属的历日与时间戳容差应分开测试。不到一分钟的差异,在取整显示中可能可以接受,却仍可能让事件落到午夜的另一侧。应记录该特定分界已知的不确定性,而不是放宽所有日期的容差。
应纳入朔与中气发生在同一参考日期的情形。即使交节瞬间早于合朔,中气也属于新的历法月份。仅按事件时间戳的先后顺序进行测试,可能漏掉这一差别。
闰月编号测试应包含2033—2034年的月序。2033年通常的八月和2034年正月都没有中气,中间的闰月却是闰十一月。把所有无中气月都定为闰月的计算,会在这些检查中失败。
历书与历史日期检查
历书分类
宜指适宜进行的事项,忌指应避免的事项。朔或农历日期相符,并不能验证这些列表。应依据所选历书约定或数据集测试查表规则,再单独检查英文事项名称。明确表示“无”的结果,也必须与数据缺失保持区别。
若某项历书分类在节气处变化,应记录其分界是交节日的起始时刻,还是节气发生的确切瞬间。应测试所选分界的前后两侧。这些月份分类不一定在农历月初改变。
干支循环同样需要明确年界。以春节为界的年名与以立春为界的年名,在两个年界之间的一段时间内可能不同。各字段应依照自身注明的约定比较。
历史日期换算
为历史文献选择换算方法之前,应确定其朝代或纪年、地点、月份名称、闰月标记,以及记录中的干支日。早期历法采用不同的天文方法和时间约定。因此,将现代计算向过去延伸,可能得到与该记录实际所用历法不同的结果。
原文转录、解释和换算后的日期,应保存在不同字段中。如果文献同时给出数字日期和干支日,应检验两者是否相符,而不是丢弃其中之一,让另一项看似成立。