|
近日對農(nóng)歷計算感興趣 , 在網(wǎng)上找了一些源碼看了看,發(fā)現(xiàn)一個廣為流傳的源碼,好像是漢王的人所寫。但是這個源碼不但參數(shù)表太大,并且運算速度很慢,不適合于用到嵌入式產(chǎn)品中。后來看到一個不錯的版本(可能為臺灣人所寫),于是對它的參數(shù)表進行了優(yōu)化,得到了一個不錯的程序,非常適合于嵌入式系統(tǒng)。 參數(shù)表所占存儲空間為:30 + 4×支持年數(shù) 經(jīng)在MSP430仿真測試,參數(shù)表占有154字節(jié),代碼占有622字節(jié),執(zhí)行一次的典型時間是1382個時鐘周期。 // ----------------------------------------------------------------- // 農(nóng)歷計算: // Copy From "西歷農(nóng)歷轉(zhuǎn)換程式 黃曉鳴 1995,7,25" // Modify : Blove // Date : 16:02 2005-12-1 // ----------------------------------------------------------------- typedef unsigned char INT8U; typedef unsigned short INT16U; typedef unsigned long INT32U; typedef struct _SolarDate_Tag_ { INT16U wYear; INT8U chMonth; INT8U chDate; }sSolarDateTag; typedef struct _LunarDate_Tag_ { INT16U wYear; INT8U chMonth; INT8U chDate; INT8U chKan; INT8U chChi; }sLunarDateTag;
// ------------------------------------------------------------------- // 農(nóng)歷計算參數(shù)位定義: // 31-25 7 : ( BaseDays )到公歷1月1日到農(nóng)歷正月初一的累積日數(shù) // 24-20 5 : ( Intercalation)閏月月份. 0==此年沒有閏月 // 19-13 7 : ( BaseKanChih )此年公歷1月1日之干支序號減 1 // 12- 0 13 : ( MonthDays )此農(nóng)歷年每月之大小, 0==小月(29日), 1==大月(30日) // ------------------------------------------------------------------- #define LPARA_MASK_BASE_DAYS 0xFE000000 #define LPARA_MASK_INTERCALATION 0x01F00000 #define LPARA_MASK_BASE_KANCHI 0x000FE000 #define LPARA_MASK_MONTH_DAYS 0x00001FFF
#define LPARA_SHIFT_BASE_DAYS 25 #define LPARA_SHIFT_INTERCALATION 20 #define LPARA_SHIFT_BASE_KANCHI 13 #define LPARA_SHIFT_MONTH_DAYS 0 #define LPara_GetBaseDays(i) ( (m_dwLunarParas[i]&LPARA_MASK_BASE_DAYS)>>LPARA_SHIFT_BASE_DAYS ) #define LPara_GetIntercalation(i) ( (m_dwLunarParas[i]&LPARA_MASK_INTERCALATION)>>LPARA_SHIFT_INTERCALATION ) #define LPara_GetBaseKanChi(i) ( (m_dwLunarParas[i]&LPARA_MASK_BASE_KANCHI)>>LPARA_SHIFT_BASE_KANCHI ) #define LPara_GetMonthDays(wYear,chMonth) \ ( (((m_dwLunarParas[wYear]&LPARA_MASK_MONTH_DAYS)>>LPARA_SHIFT_MONTH_DAYS)>>chMonth)&0x01 ) // ----------------------------------------------------------- // 農(nóng)歷計算參數(shù)表 // ----------------------------------------------------------- static const INT32U m_dwLunarParas[] = { 0x2E47752B, 0x5400952B, 0x3E012A5B, 0x2A21D55A, 0x4E02956A, // 2005 0x38733B55, 0x6003DBA4, 0x4A047B49, 0x32553A93, 0x5805DA95, 0x4206752D, 0x2C470AAD, 0x50004AAD, 0x3C90F5AA, 0x620195D2, // 2015 0x4C022DA5, 0x3662FD4A, 0x5C038D4A, 0x46042C95, 0x3044D52E, 0x54059556, 0x3E062AB5, 0x2A26D5B2, 0x500776D2, 0x3860AEA5, // 2025 0x5E015725, 0x4801F64B, 0x32528C97, 0x56035CAB, 0x4203E55A, 0x2C348AD6 // 2031 }; #define FIRSTYEAR 2001 // 參數(shù)表中的第一年 #define YEAR_NUMS ( sizeof(m_dwLunarParas) / sizeof(INT32U) ) #define LASTYEAR ( FIRSTYEAR + YEAR_NUMS - 1 ) // 參數(shù)表中的最后一年 // ----------------------------------------------------------- // 公歷年每月天數(shù)標記表 // 由高位到低位為12-1月:1表示31天,0表示30天,二月除外 // 月份: 12 11 10 9 8 7 6 5 4 3 2 1 // 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 28, 31 // 1 0 1 0 1 1 0 1 0 1 0 1 // ----------------------------------------------------------- static const INT16U m_wSolarMonthDaysFlag = 0x0AD5;
// ----------------------------------------------------------- // 公歷年每月累積天數(shù), 平年與閏年 // ----------------------------------------------------------- static const INT16U m_wSolarDays[14] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 396 }; // ----------------------------------------------------------- // 求此公歷年是否為閏年, 返回 0 為平年, 1 為閏年 // ----------------------------------------------------------- BOOL Lunar_IsIntercalation( INT16U wYear ) { if ( wYear % 400 == 0 ) return 1; else if ( wYear % 100 == 0 ) return 0; else if ( wYear % 4 == 0 ) return 1; else return 0; }
// ----------------------------------------------------------- // 農(nóng)歷計算 // ----------------------------------------------------------- int Lunar_Cal( sSolarDateTag *psSolarDate, sLunarDateTag *psLunarDate ) { INT16U wSolarMonth, wDaySum, wSolarDaysSum, im, wTmp1, wTmp2, i, wKanChiSum; BOOL bLeapFlag; INT8U chMonthDays, chYearIndex;
// 輸入?yún)?shù)的有效性檢查 if ( psSolarDate->wYear<=FIRSTYEAR || psSolarDate->wYear>LASTYEAR ) return 1; wSolarMonth = psSolarDate->chMonth - 1; if ( wSolarMonth > 11 ) return 2; bLeapFlag = Lunar_IsIntercalation( psSolarDate->wYear ); if ( wSolarMonth == 1) // 二月 { chMonthDays = bLeapFlag + 28; } else // 其他月份 { chMonthDays = 30 + ((m_wSolarMonthDaysFlag>>wSolarMonth)&0x01); } if ( psSolarDate->chDate<1 || psSolarDate->chDate>chMonthDays ) return 3; chYearIndex = psSolarDate->wYear - FIRSTYEAR; wSolarDaysSum = m_wSolarDays[wSolarMonth]; if ( wSolarMonth > 1 ) wSolarDaysSum += bLeapFlag; wDaySum = wSolarDaysSum + psSolarDate->chDate; wKanChiSum = wDaySum + LPara_GetBaseKanChi(chYearIndex); psLunarDate->chKan = wKanChiSum % 10; psLunarDate->chChi = wKanChiSum % 12; if ( wDaySum <= LPara_GetBaseDays(chYearIndex) ) { chYearIndex--; psLunarDate->wYear = psSolarDate->wYear - 1; bLeapFlag = Lunar_IsIntercalation( psLunarDate->wYear ); wSolarMonth += 12; wSolarDaysSum = m_wSolarDays[wSolarMonth]; if ( wSolarMonth > 1 ) wSolarDaysSum += bLeapFlag; wDaySum = wSolarDaysSum + psSolarDate->chDate; } else { psLunarDate->wYear = psSolarDate->wYear; } wTmp1 = LPara_GetBaseDays(chYearIndex); for ( i=0; i<13; i++ ) { wTmp2 = wTmp1 + LPara_GetMonthDays( chYearIndex, i) + 29; if ( wDaySum <= wTmp2 ) break; wTmp1 = wTmp2; } psLunarDate->chMonth = i + 1; psLunarDate->chDate = wDaySum - wTmp1; im = LPara_GetIntercalation(chYearIndex); if ( im != 0 && psLunarDate->chMonth > im) psLunarDate->chMonth--; if ( psLunarDate->chMonth > 12) psLunarDate->chMonth -= 12; return 0; } |