• 农历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
    ", iLunarYear, iLunarMonth, iLunarDay, lbIsLeapMonth);
    
        iYear = 1901;
        iMonth = 1;
        iDay = 2;
        LONG lRtn = pLunar->CalcDateDiff_01(1905, 1901);
        printf("%d
    ", lRtn);
    
        printf("
    ");
    
        for (int i=1901; i<=2050; i++)
        {
            int iDays = pLunar->GetLunarYearDays(i);
            printf("[%03d] : %d
    ", i-1900, iDays);
        }
    
        int iDaysTotal = 0;
        for (int j=1901; j<=2050; j++)
        {
            int iDays = pLunar->GetLunarYearDays(j);
            iDaysTotal += iDays;
            //printf("(%03d) : %d
    ", j-1900, iDaysTotal);
            printf("%d,", iDaysTotal);
            if (j % 10 == 0)
                printf("
    ");
        }
    }
    /*
      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、

  • 相关阅读:
    ext DateTime.js在ie下显示不全
    js 获得每周周日到周一日期
    近十年one-to-one最短路算法研究整理【转】
    虚函数(实现多态)
    函数调用机制2
    函数调用机制
    面向对象的三大特性
    矩阵类c++实现
    矩阵求逆c++实现
    解决文件大小上传限制
  • 原文地址:https://www.cnblogs.com/cppskill/p/5967141.html
Copyright © 2020-2023  润新知