农历03__ZC

Posted CppSkill

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了农历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、

 

以上是关于农历03__ZC的主要内容,如果未能解决你的问题,请参考以下文章

DrawDibDraw__ZC测试

TCP_AIO_Server_ZC_01

zlib__ZC

农历02__资料

圈圈.报告描述符__ZC记录

圈圈.ZC问题