#include <stdio.h>
#include <afx.h>
#include <windows.h>



const WORD START_YEAR =1901; 
const WORD END_YEAR   =2050; 


/****************************************************************************** 
  下面为阴历计算所需的数据,为节省存储空间,所以采用下面比较变态的存储方法. 
    
*******************************************************************************/ 
//数组gLunarDay存入阴历1901年到2100年每年中的月天数信息, 
//阴历每月只能是29或30天,一年用12(或13)个二进制位表示,对应位为1表30天,否则为29天 
WORD gLunarMonthDay[]= 
{ 
        //测试数据只有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 
   
}; 

//数组gLanarMonth存放阴历1901年到2050年闰月的月份,如没有则为0,每字节存两年 
BYTE  gLunarMonth[]= 
{ 
        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 
}; 



BOOL IsLeapYear(WORD iYear) {return !(iYear%4)&&(iYear%100) || !(iYear%400);} 


WORD  MonthDays(WORD iYear, WORD iMonth) 
{ 
        switch(iMonth) 
        { 
        case 1:case 3:case 5:case 7:case 8:case 10:case 12: 
                return 31; 
                break; 
        case 4:case 6:case 9:case 11: 
                return 30; 
                break; 
        case 2: 
                //如果是闰年 
                if(IsLeapYear(iYear)) 
                        return 29; 
                else 
                        return 28; 
                break; 
        } 
        return 0; 
} 

WORD  GetLeapMonth(WORD iLunarYear) 
{ 
        BYTE &flag = gLunarMonth[(iLunarYear - START_YEAR)/2]; 
        return  (iLunarYear - START_YEAR)%2 ? flag&0x0f : flag>>4; 
} 

LONG  LunarMonthDays(WORD iLunarYear, WORD iLunarMonth) 
{ 
        if(iLunarYear < START_YEAR)  
                return 30L; 

        WORD height =0 ,low =29; 
        int iBit = 16 - iLunarMonth; 

    if(iLunarMonth > GetLeapMonth(iLunarYear) && GetLeapMonth(iLunarYear)) 
                   iBit --; 

        if(gLunarMonthDay[iLunarYear - START_YEAR] & (1<<iBit)) 
                low ++; 
             
        if(iLunarMonth == GetLeapMonth(iLunarYear)) 
                if(gLunarMonthDay[iLunarYear - START_YEAR] & (1<< (iBit -1))) 
                     height =30; 
                else  
                         height =29; 

        return MAKELONG(low, height); 
} 

WORD  LunarYearDays(WORD iLunarYear) 
{ 
        /* 
        WORD days=348 ; //12*29 
        int  month = 12 ; 

        //如果iYear年有闰月,则为13个月 
    if(gLanarMonth[iYear - START_YEAR])  
                month ++; 
    //如果某月是三十天则days++ 
        while(month >=0 && (gLanarMonthDay[iYear - START_YEAR] & (1 << (16 - month)))) 
        {    
                days ++;  
            month --; 
        } 
        return days; 
        */ 
        WORD days =0; 
        for(WORD  i=1; i<=12; i++) 
        {  
        LONG  tmp = LunarMonthDays(iLunarYear ,i);  
                days += HIWORD(tmp); 
                days += LOWORD(tmp); 
        } 
    return days; 
} 


// add by handong: 显示 生肖  及 干支 纪年 :   pShX(兔(又名得到之兔))  pGZhi 甲子 
void FormatShengXiao(WORD  iYear, char *pShX, char *pGZhi) 
{        
        char szText1[]="甲乙丙丁戊己庚辛壬癸"; 
        char szText2[]="子丑寅卯辰巳午未申酉戌亥"; 
        char szText3[]="鼠牛虎免龙蛇马羊猴鸡狗猪"; 
        char szText4[]="屋上之鼠海内之牛山林之虎"; 
        memcpy(pGZhi,  szText1+((iYear-4)%10)*2,2); 
        memcpy(pGZhi+2,szText2+((iYear-4)%12)*2,2); 
        pGZhi[4]=0; 
         
        memcpy(pShX,szText3+((iYear-4)%12)*2,2); 
        strcpy(pShX+2,"(又名:)"); 
         
}         
//格式化农历中的year
void FormatLunarYear(WORD  iYear, char *pBuffer) 
{        
        char szText1[]="甲乙丙丁戊己庚辛壬癸"; 
        char szText2[]="子丑寅卯辰巳午未申酉戌亥"; 
        char szText3[]="鼠牛虎免龙蛇马羊猴鸡狗猪"; 

        memcpy(pBuffer,  szText1+((iYear-4)%10)*2,2); 
        memcpy(pBuffer+2,szText2+((iYear-4)%12)*2,2); 
        pBuffer[4]=' '; 
        memcpy(pBuffer+5,szText3+((iYear-4)%12)*2,2); 
        strcpy(pBuffer+7,"年"); 
} 
//格式化农历中的month
void FormatMonth(WORD iMonth, char *pBuffer, BOOL bLunar) 
{ 
   if(!bLunar && iMonth==1) 
   { 
           strcpy(pBuffer, " 正月"); 
           return; 
   } 

   char szText[]="正二三四五六七八九十"; 
   if(iMonth<=10) 
   { 
           memcpy(pBuffer, " ", 2); 
       memcpy(pBuffer+2, szText + (iMonth -1)*2, 2); 
       strcpy(pBuffer+4 , "月"); 
           return; 
   } 
   if (iMonth == 11) 
           strcpy(pBuffer, "冬月"); 
   else 
           strcpy(pBuffer, "腊月"); 
    //strcpy(pBuffer+4 , "月"); 

    
} 
//格式化农历中的day
void FormatLunarDay(WORD  iDay, char *pBuffer) 
{ 
    char szText1[]="初十廿三"; 
        char szText2[]="一二三四五六七八九十"; 
        if(iDay != 20 && iDay !=30) 
        { 
                memcpy(pBuffer, szText1 + (iDay-1)/10*2 ,2); 
                memcpy(pBuffer+2, szText2 + ((iDay-1)%10)*2 ,2); 
                pBuffer[4]='\0'; 
        } 
        else 
        { 
        memcpy(pBuffer, szText1 + iDay/10*2, 2); 
                strcpy(pBuffer+2, szText2 +18); 
        } 
} 



extern "C" _declspec(dllexport) void  l_CalcLunarDate(WORD &iYear, WORD &iMonth ,WORD &iDay, LONG iSpanDays) 
{ 
        //阳历1901年2月19日为阴历1901年正月初一 
        //阳历1901年1月1日到2月19日共有49天 
        if(iSpanDays <49) 
        { 
                iYear  = START_YEAR-1; 
                if(iSpanDays <19) 
                {  
                  iMonth = 11;   
                  iDay   = 11+WORD(iSpanDays); 
                } 
                else 
                { 
                        iMonth = 12; 
                        iDay   =  WORD(iSpanDays) -18; 
                } 
                return ; 
        } 
        //下面从阴历1901年正月初一算起 
        iSpanDays -=49; 
    iYear  = START_YEAR; 
        iMonth = 1; 
        iDay   = 1; 
        //计算年 
        LONG tmp = LunarYearDays(iYear);  
        while(iSpanDays >= tmp) 
        { 
                iSpanDays -= tmp; 
                tmp = LunarYearDays(++iYear); 
        } 
    //计算月 
        tmp = LOWORD(LunarMonthDays(iYear, iMonth)); 
        while(iSpanDays >= tmp) 
        { 
                iSpanDays -= tmp; 
            if(iMonth == GetLeapMonth(iYear)) 
                { 
                        tmp  = HIWORD(LunarMonthDays(iYear, iMonth)); 
                        if(iSpanDays < tmp)      
                                break; 
                        iSpanDays -= tmp; 
                } 
                tmp = LOWORD(LunarMonthDays(iYear, ++iMonth)); 
        } 
        //计算日 
        iDay += WORD(iSpanDays); 
} 
extern "C" _declspec(dllexport) LONG  CalcDateDiff(WORD iEndYear, WORD iEndMonth, WORD iEndDay, 
                                    WORD  iStartYear, WORD iStartMonth, WORD iStartDay) 
{ 
        WORD monthday[]={0, 31, 59 ,90, 120, 151, 181, 212, 243, 273, 304, 334};  

        //计算两个年份1月1日之间相差的天数 
        LONG iDiffDays =(iEndYear - iStartYear)*365; 
        iDiffDays += (iEndYear-1)/4 - (iStartYear-1)/4; 
        iDiffDays -= ((iEndYear-1)/100 - (iStartYear-1)/100); 
        iDiffDays += (iEndYear-1)/400 - (iStartYear-1)/400; 

    //加上iEndYear年1月1日到iEndMonth月iEndDay日之间的天数 
    iDiffDays += monthday[iEndMonth-1] + 
                                           (IsLeapYear(iEndYear)&&iEndMonth>2? 1: 0); 
    iDiffDays += iEndDay; 

        //减去iStartYear年1月1日到iStartMonth月iStartDay日之间的天数 
        iDiffDays -= (monthday[iStartMonth-1] +  
                                  (IsLeapYear(iStartYear)&&iStartMonth>2 ? 1: 0)); 
    iDiffDays -= iStartDay;      
        return iDiffDays; 
} 

extern "C" _declspec(dllexport) void GetLunarDate(WORD iYear, WORD iMonth, WORD iDay, 
                                     WORD &iLunarYear, WORD &iLunarMonth, WORD &iLunarDay) 
{ 
   l_CalcLunarDate(iLunarYear, iLunarMonth, iLunarDay,  
                                      CalcDateDiff(iYear, iMonth, iDay,1901,01,01)); 
 
} 


//获取农历LunarY年LunarM月LunarD日公历日期(Y年M月D日)
extern "C" _declspec(dllexport) void CovertLunarToSolar(WORD LunarY,WORD LunarM,WORD LunarD,WORD &Y,WORD &M,WORD &D) 
{ 
        CTime TmpDate(LunarY,LunarM,LunarD,12,12,12); 
        CTime Up,Down; 
        CTimeSpan       InterveDate(60,0,0,0); //前后2个月天搜索 
        CTimeSpan       OneDay(1,0,0,0); 
        WORD Year, Mon, Day; 
        WORD LunarYear,LunarMon,LunarDay; 
         
        Up = TmpDate + InterveDate; 
        Down = TmpDate - InterveDate; 
         
        CTimeSpan Days=Up-Down; 
         
        int Len = Days.GetDays(); 
        TmpDate=Down; 
        for(int i=0; i<Len; i++) 
        { 
                TmpDate = TmpDate + OneDay; 
                Year = TmpDate.GetYear(); Mon = TmpDate.GetMonth();  Day = TmpDate.GetDay(); 
                GetLunarDate(Year, Mon, Day, LunarYear, LunarMon, LunarDay); 
                if( (LunarYear==LunarY) && (LunarMon==LunarM) && (LunarDay==LunarD) )//found 
                { 
                        Y=Year; M=Mon; D=Day; 
                        return;                                          
                } 
        } 
  
}