也談農歷置閏


在看王曉華所著《算法的樂趣》(王曉華著. 算法的樂趣[M]. 北京:人民郵電出版社, 2015.04.)第11章中給出的農歷程序源代碼時,發現在農歷置閏方面似乎有點問題,值得商榷。

書中給出的農歷閏月設置規則與《GB/T 33661-2017 農歷的編算和頒行》相一致,但長篇大論的比國標長多了,所以直接引用國標原文吧:

4 農歷的編排規則
4.1 以北京時間為標准時間。
4.2 朔日為農歷月的第一個農歷日。
4.3 包含節氣冬至在內的農歷月為農歷十一月。
4.4 若從某個農歷十一月開始到下一個農歷十一月(不含)之間有13個農歷月,則需要置閏。置閏規則為:取其中最先出現的一個不包含中氣的農歷月為農歷閏月。
4.5 農歷十一月之后第2個(不計閏月)農歷月為農歷年的起始月。

書中判斷是否需要置閏的代碼是CChineseCalendar::CalcLeapChnMonth(),沒有該書或沒有該書源代碼的可以看這里,有相同的文字說明和源代碼:
https://blog.csdn.net/orbit/article/details/9337377

CalcLeapChnMonth函數代碼初看沒有問題,與國標中4.4相一致,但其實存在一個邏輯漏洞: 代碼中的m_NewMoonJD數組是從前一年的十一月(冬至月)開始的,因此代碼

if(int(m_NewMoonJD[13] + 0.5) <= int(m_SolarTermsJD[24] + 0.5)) //第13月的月末沒有超過冬至,說明今年需要閏一個月

考慮了本年前11個月是否需要置閏,但漏掉了另外一個考慮選項:本年的第12個月(m_NewMoonJD[14])是否需要置閏?

要判斷本年第12個月是否需要置閏(閏冬月),就需要從本年冬至月計算到下年冬至月,發現有13個月時再看本年第12個月是否無中氣。簡單一點說,其實就是在用書中的代碼計算發現本年無閏月時,還要用相同的代碼再算一遍第二年的閏月看是不是本年的第十二個月。第二遍計算時m_NewMoonJD數組中存儲的是從本年冬至到下年冬至之間的朔時刻。而在用現有的代碼計算發現本年需要置閏時,也要檢查一下去年的冬月是否已經閏過,如果閏過就別再閏了。

如果不做這樣的修正,在碰到2033年這樣需要閏冬月的年份就會出現錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM