农历03__ZC
代码,改自 农历01(http://www.cnblogs.com/cppskill/p/5930558.html)
1、main.cpp
#include "Lunar_ZC.h" #include <stdio.h> void main() { //WORD iYear = 2016, iMonth = 10, iDay = 16; //WORD iYear = 1903, iMonth = 5, iDay = 27; // 阴历为 1903年5月初一 WORD iYear = 1903, iMonth = 6, iDay = 25; // 阴历为 1903年闰5月初一 WORD iLunarYear = 0, iLunarMonth = 0, iLunarDay = 0; BOOL lbIsLeapMonth = 0; TLunar* pLunar = new TLunar(); pLunar->l_CalcLunarDate(iLunarYear, iLunarMonth, iLunarDay, lbIsLeapMonth, pLunar->CalcDateDiff(iYear, iMonth, iDay)); printf("%d,%d,%d, 闰月?:%d\n", iLunarYear, iLunarMonth, iLunarDay, lbIsLeapMonth); iYear = 1901; iMonth = 1; iDay = 2; LONG lRtn = pLunar->CalcDateDiff_01(1905, 1901); printf("%d\n", lRtn); printf("\n"); for (int i=1901; i<=2050; i++) { int iDays = pLunar->GetLunarYearDays(i); printf("[%03d] : %d\n", i-1900, iDays); } int iDaysTotal = 0; for (int j=1901; j<=2050; j++) { int iDays = pLunar->GetLunarYearDays(j); iDaysTotal += iDays; //printf("(%03d) : %d\n", j-1900, iDaysTotal); printf("%d,", iDaysTotal); if (j % 10 == 0) printf("\n"); } } /* 354, 709, 1092, 1446, 1801, 2185, 2539, 2894, 3278, 3632, 4016, 4370, 4724, 5108, 5463, 5817, 6201, 6556, 6940, 7294, 7648, 8032, 8386, 8740, 9125, 9479, 9834,10218,10572,10955, 11309,11664,12048,12403,12757,13141,13495,13879,14233,14587, 14971,15326,15680,16065,16419,16773,17157,17511,17895,18249, 18604,18988,19342,19697,20081,20435,20818,21173,21527,21911, 22266,22620,23004,23359,23712,24096,24451,24835,25189,25544, 25928,26282,26636,27020,27374,27758,28112,28467,28851,29206, 29560,29944,30298,30682,31036,31390,31774,32129,32484,32868, 33222,33576,33959,34314,34698,35052,35407,35791,36145,36499, 36883,37237,37592,37976,38330,38715,39069,39423,39807,40161, 40515,40899,41254,41638,41992,42347,42731,43085,43439,43823, 44177,44532,44916,45270,45654,46008,46362,46746,47101,47455, 47839,48194,48578,48932,49286,49670,50024,50378,50762,51117, 51472,51856,52210,52594,52948,53302,53686,54040,54395,54779, */
2、类 TLunar
2.1、Lunar_ZC.h
#ifndef __LUNAR_ZC_20161015__ #define __LUNAR_ZC_20161015__ #include <windows.h> extern const WORD START_YEAR; extern const WORD END_YEAR ; class TLunar { public: WORD m_wYear, m_wMonth, m_wDay; TLunar(WORD _wYear, WORD _wMonth, WORD _wDay); TLunar(); BOOL SetDate(WORD _wYear , WORD _wMonth , WORD _wDay); void l_InitData(); //=====================================================================================// //返回 公历_wYear年_wMonth月的天数 1年1月 --- 65535年12月 static WORD MonthDays(WORD _wYear, WORD _wMonth); //判断 公历_wYear是不是闰年 static BOOL IsLeapYear(WORD _wYear) { return ( !(_wYear%4)&&(_wYear%100) ) || ( !(_wYear%400) ); } //=====================================================================================// static LONG CalcDateDiff_01(WORD _wEndYear, WORD _wStartYear); //计算 公历两个日期间相差的天数 1年1月1日 --- 65535年12月31日 static LONG CalcDateDiff(WORD _wEndYear, WORD _wEndMonth, WORD _wEndDay, WORD _wStartYear = START_YEAR, WORD _wStartMonth =1, WORD _wStartDay =1); public: //计算从 公历1901年1月1日过iSpanDays天后的 阴历日期 static void l_CalcLunarDate(WORD &_wYear, WORD &_wMonth, WORD &_wDay, BOOL &_lbIsLeepMonth, LONG _lSpanDays); //返回阴历iLunarYear年的闰月月份,如没有返回0 // 1901年1月---2050年12月 static WORD GetLunarLeapMonth(WORD _wLunarYear); //返回阴历_wLunarYear年阴历_wLunarMonth月的天数, //如果_wLunarMonth为闰月,高字为第二个_wLunarMonth月的天数,否则高字为0 。 // 1901年1月---2050年12月 static LONG GetLunarMonthDays(WORD _wLunarYear, WORD _wLunarMonth); //返回阴历iLunarYear年的总天数 // 1901年1月---2050年12月 static WORD GetLunarYearDays(WORD _wLunarYear); }; #endif// __LUNAR_ZC_20161015__
2.2、Lunar_ZC.cpp
#include "Lunar_ZC.h" #include <windows.h> /* ZC: 中/英文 农历 : Lunar calendar 闰月 : Leap month */ extern WORD g_wordsLunarMonthDay[]; extern BYTE g_bytesLunarMonth[]; const WORD START_YEAR =1901; const WORD END_YEAR =2050; //===========================================================================// TLunar::TLunar(WORD _wYear, WORD _wMonth, WORD _wDay) { if(! SetDate(_wYear, _wMonth, _wDay)) l_InitData(); } //===========================================================================// TLunar::TLunar() { l_InitData(); } //===========================================================================// BOOL TLunar::SetDate(WORD _wYear, WORD _wMonth, WORD _wDay) { if (_wYear < START_YEAR || _wYear > END_YEAR || _wMonth <1 || _wMonth >12) return FALSE; if (_wDay <1 || _wDay > MonthDays(_wYear, _wMonth)) return FALSE; m_wYear = _wYear; m_wMonth = _wMonth; m_wDay = _wDay; return TRUE; } //===========================================================================// void TLunar::l_InitData() { SYSTEMTIME systime; ::GetSystemTime(&systime); m_wYear = systime.wYear; m_wMonth = systime.wMonth; m_wDay = systime.wDay; } //===========================================================================// WORD TLunar::MonthDays(WORD _wYear, WORD _wMonth) { switch(_wMonth) { case 1: //一 (月) case 3: //三 (月) case 5: //五 (月) case 7: //七 (月) case 8: //八 (月) case 10://十 (月) case 12://十二(月) return 31; case 4: //四 (月) case 6: //六 (月) case 9: //九 (月) case 11://十一(月) return 30; case 2: //二 (月) //如果是闰年 if(IsLeapYear(_wYear)) return 29; else return 28; } return 0; } LONG TLunar::CalcDateDiff_01(WORD _wEndYear, WORD _wStartYear) { //计算两个年份1月1日之间相差的天数 // ZC: 这里应该是处理 闰年多出来的天数 LONG lDiffDays01 = (_wEndYear-1)/4 - (_wStartYear-1)/4; LONG lDiffDays02 = ( (_wEndYear-1)/100 - (_wStartYear-1)/100 ); LONG lDiffDays03 = (_wEndYear-1)/400 - (_wStartYear-1)/400; LONG lDiffDays = (_wEndYear - _wStartYear) * 365; lDiffDays += lDiffDays01; lDiffDays -= lDiffDays02; lDiffDays += lDiffDays03; return lDiffDays; } //===========================================================================// LONG TLunar::CalcDateDiff(WORD _wEndYear, WORD _wEndMonth, WORD _wEndDay, WORD _wStartYear, WORD _wStartMonth, WORD _wStartDay) { WORD monthday[] = {0, 31, 59 ,90, 120, 151, 181, 212, 243, 273, 304, 334}; //计算两个年份1月1日之间相差的天数 LONG lDiffDays = CalcDateDiff_01(_wEndYear, _wStartYear); //加上iEndYear年1月1日到iEndMonth月iEndDay日之间的天数 lDiffDays += monthday[_wEndMonth-1] + ( IsLeapYear(_wEndYear) && (_wEndMonth > 2 ? 1: 0) ); lDiffDays += _wEndDay; //减去iStartYear年1月1日到iStartMonth月iStartDay日之间的天数 lDiffDays -= monthday[_wStartMonth-1] + ( IsLeapYear(_wStartYear) && (_wStartMonth > 2 ? 1 : 0) ); lDiffDays -= _wStartDay; return lDiffDays; } //===========================================================================// void TLunar::l_CalcLunarDate(WORD &_wYear, WORD &_wMonth, WORD &_wDay, BOOL &_lbIsLeepMonth, LONG _lSpanDays) { //阳历1901年2月19日 为 阴历1901年正月初一 //阳历1901年1月1日 到 2月19日 共有49天 if(_lSpanDays <49) { _wYear = START_YEAR - 1; if(_lSpanDays < 19) { _wMonth = 11; _wDay = 11 + WORD(_lSpanDays); } else { _wMonth = 12; _wDay = WORD(_lSpanDays) - 18; } return; } //下面从阴历1901年正月初一算起 _lSpanDays -= 49; _wYear = START_YEAR; _wMonth = 1; _wDay = 1; //计算年 LONG tmp = GetLunarYearDays(_wYear); while(_lSpanDays >= tmp) { _lSpanDays -= tmp; tmp = GetLunarYearDays(++_wYear); } //计算月 tmp = LOWORD(GetLunarMonthDays(_wYear, _wMonth)); while(_lSpanDays >= tmp) { _lSpanDays -= tmp; if(_wMonth == GetLunarLeapMonth(_wYear)) { tmp = HIWORD(GetLunarMonthDays(_wYear, _wMonth)); if(_lSpanDays < tmp) { _lbIsLeepMonth = true; break; } _lSpanDays -= tmp; } tmp = LOWORD(GetLunarMonthDays(_wYear, ++_wMonth)); } //计算日 _wDay += WORD(_lSpanDays); } //===========================================================================// WORD TLunar::GetLunarLeapMonth(WORD _wLunarYear) { BYTE &flag = g_bytesLunarMonth[(_wLunarYear - START_YEAR)/2]; // ZC: 这里&的作用 和 函数参数中使用&的作用 一样。 return (_wLunarYear - START_YEAR)%2 ? flag&0x0f : flag>>4; } //===========================================================================// /* ZC: 算法注释: (一年最多只有一个闰月) 以1903年为例,5月为闰月,每月的天数信息为0101 0010 0110 1000 . if (iLunarMonth==6) :则一开始iBit==16-6=10,∵5月是闰月,∴ 1<<10指向的是闰5月的天数信息,1<<9指向的才是6月的天数信息,∴会有“iBit--”的操作。 if (iLunarMonth==5) :则一开始iBit==16-5=11,∵5月是闰月,∴ 1<<11指向的是第1个5月的天数信息,1<<(11-1)指向的才是闰5月的天数信息。 */ LONG TLunar::GetLunarMonthDays(WORD _wLunarYear, WORD _wLunarMonth) { if (_wLunarYear < START_YEAR) return 30L; WORD high =0, low =29; int iBit = 16 - _wLunarMonth; WORD wLeapMonth = GetLunarLeapMonth(_wLunarYear); if ( (_wLunarMonth > wLeapMonth) && (wLeapMonth != 0) ) { iBit --; } if(g_wordsLunarMonthDay[_wLunarYear - START_YEAR] & (1<<iBit)) { low = 30; }// ZC: 每个月的天数只可能是2个值中的1个:29/30 if(_wLunarMonth == wLeapMonth) { if(g_wordsLunarMonthDay[_wLunarYear - START_YEAR] & (1<< (iBit -1))) { high =30; } else { high =29; } } return MAKELONG(low, high); } //===========================================================================// WORD TLunar::GetLunarYearDays(WORD _wLunarYear) { WORD days =0; for(WORD i=1; i<=12; i++) { LONG tmp = GetLunarMonthDays(_wLunarYear ,i); days += HIWORD(tmp); days += LOWORD(tmp); } return days; } /* ZC: 他是这样存储的:(1个WORD存放1年的信息, 实际只是用了高位的12/13个bit位)(高位存放前一个月的信息, 低位存放后一个月的信息) 1901年信息:0x4ae0 ==> 高位->地位的比特位为: 0100 1010 1110 0000, 由g_bytesLunarMonth中的信息可知,该年不是闰年,于是12个月的天数信息依次为0100 1010 1110 1902年信息:0xa570 ==> 高位->地位的比特位为: 1010 0101 0111 0000, 由g_bytesLunarMonth中的信息可知,该年不是闰年,于是12个月的天数信息依次为1010 0101 0111 1903年信息:0x5268 ==> 高位->地位的比特位为: 0101 0010 0110 1000, 由g_bytesLunarMonth中的信息可知,该年 是闰年,于是13个月的天数信息依次为0101 0010 0110 1 我的想法是: 低位存放前一个月的信息,高位存放后一个月的信息,这样在内存中每个WORD从低位到高位 都是1->12月的信息排列(后面也留有空位)。 他的做法 和 我的想法 不一致... */ /****************************************************************************** 下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方法. *******************************************************************************/ //数组gLunarDay存入阴历1901年到2100年每年中的月天数信息, //阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表30天,否则为29天 WORD g_wordsLunarMonthDay[]= { //测试数据只有1901.1.1 --2050.12.31 0X4ae0, 0Xa570, 0X5268, 0Xd260, 0Xd950, 0X6aa8, 0X56a0, 0X9ad0, 0X4ae8, 0X4ae0, //1910 0Xa4d8, 0Xa4d0, 0Xd250, 0Xd548, 0Xb550, 0X56a0, 0X96d0, 0X95b0, 0X49b8, 0X49b0, //1920 0Xa4b0, 0Xb258, 0X6a50, 0X6d40, 0Xada8, 0X2b60, 0X9570, 0X4978, 0X4970, 0X64b0, //1930 0Xd4a0, 0Xea50, 0X6d48, 0X5ad0, 0X2b60, 0X9370, 0X92e0, 0Xc968, 0Xc950, 0Xd4a0, //1940 0Xda50, 0Xb550, 0X56a0, 0Xaad8, 0X25d0, 0X92d0, 0Xc958, 0Xa950, 0Xb4a8, 0X6ca0, //1950 0Xb550, 0X55a8, 0X4da0, 0Xa5b0, 0X52b8, 0X52b0, 0Xa950, 0Xe950, 0X6aa0, 0Xad50, //1960 0Xab50, 0X4b60, 0Xa570, 0Xa570, 0X5260, 0Xe930, 0Xd950, 0X5aa8, 0X56a0, 0X96d0, //1970 0X4ae8, 0X4ad0, 0Xa4d0, 0Xd268, 0Xd250, 0Xd528, 0Xb540, 0Xb6a0, 0X96d0, 0X95b0, //1980 0X49b0, 0Xa4b8, 0Xa4b0, 0Xb258, 0X6a50, 0X6d40, 0Xada0, 0Xab60, 0X9370, 0X4978, //1990 0X4970, 0X64b0, 0X6a50, 0Xea50, 0X6b28, 0X5ac0, 0Xab60, 0X9368, 0X92e0, 0Xc960, //2000 0Xd4a8, 0Xd4a0, 0Xda50, 0X5aa8, 0X56a0, 0Xaad8, 0X25d0, 0X92d0, 0Xc958, 0Xa950, //2010 0Xb4a0, 0Xb550, 0Xb550, 0X55a8, 0X4ba0, 0Xa5b0, 0X52b8, 0X52b0, 0Xa930, 0X74a8, //2020 0X6aa0, 0Xad50, 0X4da8, 0X4b60, 0X9570, 0Xa4e0, 0Xd260, 0Xe930, 0Xd530, 0X5aa0, //2030 0X6b50, 0X96d0, 0X4ae8, 0X4ad0, 0Xa4d0, 0Xd258, 0Xd250, 0Xd520, 0Xdaa0, 0Xb5a0, //2040 0X56d0, 0X4ad8, 0X49b0, 0Xa4b8, 0Xa4b0, 0Xaa50, 0Xb528, 0X6d20, 0Xada0, 0X55b0, //2050 }; /* ZC: 他是这样存储的:(高位 放的是 前一年的信息; 低位 放的是 后一年的信息) 1901,1902年的信息为 0x00 ==> 说明 这两年都不是闰年 1903,1904年的信息为 0x50 ==> 1903:5月是闰月; 1904不是闰年 我的想法是: 低位存放前一年信息,高位存放后一年信息,这样在内存中从低位到高位 就是1901->2050年的信息排列。 他的做法 和 我的想法 不一致... */ //数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节存两年 BYTE g_bytesLunarMonth[]= { 0X00, 0X50, 0X04, 0X00, 0X20, //1910 0X60, 0X05, 0X00, 0X20, 0X70, //1920 0X05, 0X00, 0X40, 0X02, 0X06, //1930 0X00, 0X50, 0X03, 0X07, 0X00, //1940 0X60, 0X04, 0X00, 0X20, 0X70, //1950 0X05, 0X00, 0X30, 0X80, 0X06, //1960 0X00, 0X40, 0X03, 0X07, 0X00, //1970 0X50, 0X04, 0X08, 0X00, 0X60, //1980 0X04, 0X0a, 0X00, 0X60, 0X05, //1990 0X00, 0X30, 0X80, 0X05, 0X00, //2000 0X40, 0X02, 0X07, 0X00, 0X50, //2010 0X04, 0X09, 0X00, 0X60, 0X04, //2020 0X00, 0X20, 0X60, 0X05, 0X00, //2030 0X30, 0Xb0, 0X06, 0X00, 0X50, //2040 0X02, 0X07, 0X00, 0X50, 0X03 //2050 };
3、
4、
5、