20歲小夥C++實現農曆演算法,程式碼功底高深莫測!
這篇文章主要介紹了C++計算中國農曆的深入淺析,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

image
所謂的“天文演算法”,就是利用經典力學定律推導行星運轉軌道,對任意時刻的行星位置進行精確計算,從而獲得某種天文現象發生時的時間,本文介紹的農曆年歷推算是在已經通過天文演算法獲得了精確的節氣時間和日月合朔時間的基礎上進行的。
加小編C/C++程式設計學習群:825414254獲取C++專案資料

image
由農曆曆法規則可知,上一個公曆年的冬至()所在的朔望月是上一個農曆年的十一月(冬月),所以在進行節氣計算時,需要計算包括上一年冬至節氣在內的二十五個節氣,才能對應上上一個農曆年的十一月和當前農曆年的十一月。在計算與之對應的朔日時,考慮到有閏月的情況,需要從上一年冬至節氣前的第一個朔日,連續計算15個朔日才能保證覆蓋兩個冬至之間的一整年時間,圖(1)顯示了2011年沒有閏月的情況下朔日和冬至的關係:

image
圖(1)沒有閏月情況下朔日與冬至節氣關係圖
圖中上排數字是公曆月的編號,黑色圓點代表朔日,黑色三角形代表冬至節氣。圖(2)顯示了2012年有閏月的情況下朔日和冬至的關係:

image
圖(2)有閏月情況下朔日與冬至節氣關係圖
通過計算得到能夠覆蓋兩個冬至節氣的所有朔日時間後,就可以著手建立公曆日期與農曆日期的對應關係。以圖(1)所示的2011年為例,首先根據計算得到的15個朔日(2011年只會用到其中的前14個時間)時間,建立與2011年(公曆年)有關的朔望月關係表:

image
表(2)2011年朔望月與公曆日期關係表
首先是計算節氣時間的函式:
<pre style="margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
5 double CalculateSolarTerms(int year, int angle);
</pre>
這個函式用於計算指定的年份(year引數)中,太陽在黃道上執行(視運動)到指定角度時的時間,angle可以設定節氣發生時的角度,比如CalculateSolarTerms(2011, 270)就是計算2011年冬至的時間。
接下來介紹計算日月合朔時間的函式:
<pre style="margin: 0px; padding: 0px; border: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-weight: 400; font-stretch: inherit; font-size: 18px; line-height: inherit; font-family: inherit; vertical-align: baseline; word-break: break-word; color: rgb(93, 93, 93); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
8 double CalculateMoonShuoJD(double tdJD);
</pre>
這個函式返回指定時間附近的朔日時間,搜尋的範圍是tdJD引數指定時間的前一天到後29.5305天,tdJD引數和返回值的時間型別都是儒略日
生成指定公曆年份的公曆和農曆的雙歷年歷的流程如下:

image
GetAllSolarTermsJD()函式從指定年份的指定節氣開始,連續計算25個節氣時間,時間可以跨年份,內部判斷過冬至節氣後自動轉到下一年的節氣繼續計算:

image
start引數是節氣的索引,定義二十四節氣的索引如下:

image
節氣索引乘以15就是節氣在黃道上對應的度數。GetNewMoonJDs()函式從指定時間開始連續計算15個朔日時間,從第一個冬至節氣前的第一個朔日開始。15個朔日可以形成14個完整的朔望月,保證在有閏月的情況下也能包含兩個冬至節氣:

image
BuildAllChnMonthInfo()函式根據15個朔日時間組成14個朔望月,根據相鄰朔日的間隔計算出農曆月天數用來判定大小月,並且從“十一月”開始依次為每個朔望月命名(月建名稱):

image
如果節氣和朔日發生在同一天,CalcLeapChnMonth()函式採用的是民間曆法的規則,與現行曆法一致:

image
從理論上講,本文介紹的演算法在精度允許的範圍內可以計算前後幾千年的農曆年歷,但是對古代的農曆計算需要小心。
根據本文介紹的演算法編寫的日曆小程式,沒有太多的功能,主要是為了驗證演算法,因為沒有歷史資料用於修正結果,因此不支援1601年以前的農曆計算(也就是說按照天文演算法計算出來的結果可能和實際歷史上的歷法不符)。

image