如何驗證農曆計算
參考日期
農曆日期換算、節氣時刻、曆書分類和界面行為,應分別驗證。其中一項相符,並不能證明其他各項也正確。一組有用的檢查應同時涵蓋月界、年界和月內日期。
選擇一個獨立的參考來源,明確其曆法約定和覆蓋範圍。使用同一計算引擎的另一個網站,可能會重複同樣的錯誤。將參考資料的版本與預期數值一併記錄,以便日後追溯變化。
本站支持公元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年正月都沒有中氣,中間的閏月卻是閏十一月。把所有無中氣月都定為閏月的計算,會在這些檢查中失敗。
曆書與歷史日期檢查
曆書分類
宜指適宜進行的事項,忌指應避免的事項。朔或農曆日期相符,並不能驗證這些列表。應依據所選曆書約定或數據集測試查表規則,再單獨檢查英文事項名稱。明確表示“無”的結果,也必須與數據缺失保持區別。
若某項曆書分類在節氣處變化,應記錄其分界是交節日的起始時刻,還是節氣發生的確切瞬間。應測試所選分界的前後兩側。這些月份分類不一定在農曆月初改變。
干支循環同樣需要明確年界。以春節為界的年名與以立春為界的年名,在兩個年界之間的一段時間內可能不同。各字段應依照自身註明的約定比較。
歷史日期換算
為歷史文獻選擇換算方法之前,應確定其朝代或紀年、地點、月份名稱、閏月標記,以及記錄中的干支日。早期曆法採用不同的天文方法和時間約定。因此,將現代計算向過去延伸,可能得到與該記錄實際所用曆法不同的結果。
原文轉錄、解釋和換算後的日期,應保存在不同字段中。如果文獻同時給出數字日期和干支日,應檢驗兩者是否相符,而不是丟棄其中之一,讓另一項看似成立。