阴历阳历相互转换c代码

#include <stdio.h>

//lingbofeiyun

//email:charlay_yu@163.com

int glo_year,glo_month,glo_day;//作为全局变量向main函数返回年月日的数据,主要用于两个转换函数
/*
下面是公历年对应的农历年数据,每年三字节,数据格式为:
第一字节位7至位4 表示闰月月份,值为0 表示无闰月,位3至位0,对应农历1至4月的大小月。对应的位为1表示本农历月大(30 天),为0 表示小(29 天)。
第二字节位7至位0 对应农历5至12月的大小月,对应的位为1表示本农历月大(30 天),为0 表示小(29 天)。
第三字节位7 表示农历第13个月的大小月份。对应的位为1表示本农历月大(30 天),为0 表示小(29 天)。位6至位5 表示春节的公历月份,位4至位0 表示春节的公历日期。于是得到阳历的几月几日是春节。
*/

char year_code[597]={
                    0x04,0xAe,0x53,    //1901
                    0x0A,0x57,0x48,    //1902
                    0x55,0x26,0xBd,    //1903
                    0x0d,0x26,0x50,    //1904
                    0x0d,0x95,0x44,    //1905
                    0x46,0xAA,0xB9,    //1906
                    0x05,0x6A,0x4d,    //1907
                    0x09,0xAd,0x42,    //1908
                    0x24,0xAe,0xB6,    //1909
                    0x04,0xAe,0x4A,    //1910
                    0x6A,0x4d,0xBe,    //1911
                    0x0A,0x4d,0x52,    //1912
                    0x0d,0x25,0x46,    //1913
                    0x5d,0x52,0xBA,    //1914
                    0x0B,0x54,0x4e,    //1915
                    0x0d,0x6A,0x43,    //1916
                    0x29,0x6d,0x37,    //1917
                    0x09,0x5B,0x4B,    //1918
                    0x74,0x9B,0xC1,    //1919
                    0x04,0x97,0x54,    //1920
                    0x0A,0x4B,0x48,    //1921
                    0x5B,0x25,0xBC,    //1922
                    0x06,0xA5,0x50,    //1923
                    0x06,0xd4,0x45,    //1924
                    0x4A,0xdA,0xB8,    //1925
                    0x02,0xB6,0x4d,    //1926
                    0x09,0x57,0x42,    //1927
                    0x24,0x97,0xB7,    //1928
                    0x04,0x97,0x4A,    //1929
                    0x66,0x4B,0x3e,    //1930
                    0x0d,0x4A,0x51,    //1931
                    0x0e,0xA5,0x46,    //1932
                    0x56,0xd4,0xBA,    //1933
                    0x05,0xAd,0x4e,    //1934
                    0x02,0xB6,0x44,    //1935
                    0x39,0x37,0x38,    //1936
                    0x09,0x2e,0x4B,    //1937
                    0x7C,0x96,0xBf,    //1938
                    0x0C,0x95,0x53,    //1939
                    0x0d,0x4A,0x48,    //1940
                    0x6d,0xA5,0x3B,    //1941
                    0x0B,0x55,0x4f,    //1942
                    0x05,0x6A,0x45,    //1943
                    0x4A,0xAd,0xB9,    //1944
                    0x02,0x5d,0x4d,    //1945
                    0x09,0x2d,0x42,    //1946
                    0x2C,0x95,0xB6,    //1947
                    0x0A,0x95,0x4A,    //1948
                    0x7B,0x4A,0xBd,    //1949
                    0x06,0xCA,0x51,    //1950
                    0x0B,0x55,0x46,    //1951
                    0x55,0x5A,0xBB,    //1952
                    0x04,0xdA,0x4e,    //1953
                    0x0A,0x5B,0x43,    //1954
                    0x35,0x2B,0xB8,    //1955
                    0x05,0x2B,0x4C,    //1956
                    0x8A,0x95,0x3f,    //1957
                    0x0e,0x95,0x52,    //1958
                    0x06,0xAA,0x48,    //1959
                    0x7A,0xd5,0x3C,    //1960
                    0x0A,0xB5,0x4f,    //1961
                    0x04,0xB6,0x45,    //1962
                    0x4A,0x57,0x39,    //1963
                    0x0A,0x57,0x4d,    //1964
                    0x05,0x26,0x42,    //1965
                    0x3e,0x93,0x35,    //1966
                    0x0d,0x95,0x49,    //1967
                    0x75,0xAA,0xBe,    //1968
                    0x05,0x6A,0x51,    //1969
                    0x09,0x6d,0x46,    //1970
                    0x54,0xAe,0xBB,    //1971
                    0x04,0xAd,0x4f,    //1972
                    0x0A,0x4d,0x43,    //1973
                    0x4d,0x26,0xB7,    //1974
                    0x0d,0x25,0x4B,    //1975
                    0x8d,0x52,0xBf,    //1976
                    0x0B,0x54,0x52,    //1977
                    0x0B,0x6A,0x47,    //1978
                    0x69,0x6d,0x3C,    //1979
                    0x09,0x5B,0x50,    //1980
                    0x04,0x9B,0x45,    //1981
                    0x4A,0x4B,0xB9,    //1982
                    0x0A,0x4B,0x4d,    //1983
                    0xAB,0x25,0xC2,    //1984
                    0x06,0xA5,0x54,    //1985
                    0x06,0xd4,0x49,    //1986
                    0x6A,0xdA,0x3d,    //1987
                    0x0A,0xB6,0x51,    //1988
                    0x09,0x37,0x46,    //1989
                    0x54,0x97,0xBB,    //1990
                    0x04,0x97,0x4f,    //1991
                    0x06,0x4B,0x44,    //1992
                    0x36,0xA5,0x37,    //1993
                    0x0e,0xA5,0x4A,    //1994
                    0x86,0xB2,0xBf,    //1995
                    0x05,0xAC,0x53,    //1996
                    0x0A,0xB6,0x47,    //1997
                    0x59,0x36,0xBC,    //1998
                    0x09,0x2e,0x50,    //1999
                    0x0C,0x96,0x45,    //2000
                    0x4d,0x4A,0xB8,    //2001
                    0x0d,0x4A,0x4C,    //2002
                    0x0d,0xA5,0x41,    //2003
                    0x25,0xAA,0xB6,    //2004
                    0x05,0x6A,0x49,    //2005
                    0x7A,0xAd,0xBd,    //2006
                    0x02,0x5d,0x52,    //2007
                    0x09,0x2d,0x47,    //2008
                    0x5C,0x95,0xBA,    //2009
                    0x0A,0x95,0x4e,    //2010
                    0x0B,0x4A,0x43,    //2011
                    0x4B,0x55,0x37,    //2012
                    0x0A,0xd5,0x4A,    //2013
                    0x95,0x5A,0xBf,    //2014
                    0x04,0xBA,0x53,    //2015
                    0x0A,0x5B,0x48,    //2016
                    0x65,0x2B,0xBC,    //2017
                    0x05,0x2B,0x50,    //2018
                    0x0A,0x93,0x45,    //2019
                    0x47,0x4A,0xB9,    //2020
                    0x06,0xAA,0x4C,    //2021
                    0x0A,0xd5,0x41,    //2022
                    0x24,0xdA,0xB6,    //2023
                    0x04,0xB6,0x4A,    //2024
                    0x69,0x57,0x3d,    //2025
                    0x0A,0x4e,0x51,    //2026
                    0x0d,0x26,0x46,    //2027
                    0x5e,0x93,0x3A,    //2028
                    0x0d,0x53,0x4d,    //2029
                    0x05,0xAA,0x43,    //2030
                    0x36,0xB5,0x37,    //2031
                    0x09,0x6d,0x4B,    //2032
                    0xB4,0xAe,0xBf,    //2033
                    0x04,0xAd,0x53,    //2034
                    0x0A,0x4d,0x48,    //2035
                    0x6d,0x25,0xBC,    //2036
                    0x0d,0x25,0x4f,    //2037
                    0x0d,0x52,0x44,    //2038
                    0x5d,0xAA,0x38,    //2039
                    0x0B,0x5A,0x4C,    //2040
                    0x05,0x6d,0x41,    //2041
                    0x24,0xAd,0xB6,    //2042
                    0x04,0x9B,0x4A,    //2043
                    0x7A,0x4B,0xBe,    //2044
                    0x0A,0x4B,0x51,    //2045
                    0x0A,0xA5,0x46,    //2046
                    0x5B,0x52,0xBA,    //2047
                    0x06,0xd2,0x4e,    //2048
                    0x0A,0xdA,0x42,    //2049
                    
};
//阳历月份数据表
static char day_code[2][13]={
    {0,31,28,31,30,31,30,31,31,30,31,30,31},//非闰年月份数据
    {0,31,29,31,30,31,30,31,31,30,31,30,31},//闰年月份数据
};


/*子函数,用于读取year_code数据表中农历月的大月或小月,如果该月为大返回1,为小返回0*/
char get_moon_day(char month_p,int table_addr)
{
    char temp;
    switch (month_p){
        case 1:{temp=year_code[table_addr]&0x08;
             if (temp==0)return(0);else return(1);}
        case 2:{temp=year_code[table_addr]&0x04;
             if (temp==0)return(0);else return(1);}
        case 3:{temp=year_code[table_addr]&0x02;
             if (temp==0)return(0);else return(1);}
        case 4:{temp=year_code[table_addr]&0x01;
             if (temp==0)return(0);else return(1);}
        case 5:{temp=year_code[table_addr+1]&0x80;
             if (temp==0) return(0);else return(1);}
        case 6:{temp=year_code[table_addr+1]&0x40;
             if (temp==0)return(0);else return(1);}
        case 7:{temp=year_code[table_addr+1]&0x20;
             if (temp==0)return(0);else return(1);}
        case 8:{temp=year_code[table_addr+1]&0x10;
             if (temp==0)return(0);else return(1);}
        case 9:{temp=year_code[table_addr+1]&0x08;
             if (temp==0)return(0);else return(1);}
        case 10:{temp=year_code[table_addr+1]&0x04;
             if (temp==0)return(0);else return(1);}
        case 11:{temp=year_code[table_addr+1]&0x02;
             if (temp==0)return(0);else return(1);}
        case 12:{temp=year_code[table_addr+1]&0x01;
             if (temp==0)return(0);else return(1);}
        case 13:{temp=year_code[table_addr+2]&0x80;
             if (temp==0)return(0);else return(1);}
    }
}

/*
阳历转为阴历

阳历转阴历的算法如下:
根据阴历数据year_code可以获得春节在当年的阳历日期(春节只会在当年的阳历1月或2月份)-->
根据春节的阳历日期可以得到春节距离元旦的天数(temp3)-->
然后计算需要转换的阳历日期距离元旦的天数(temp4)-->
通过比较temp3和temp4的大小就可以得到需要转换的阳历日期是在春节前还是春节后-->
如果是在春节后(temp4-temp3)就是需要转换的阳历日期距离春节的天数,然后获取阴历从正月开始逐个月份的天数与(temp4-temp3)比较,就会得到阴历的月份和阴历的日期。在这期间会包含对闰月的处理。-->
如果是在春节前(temp3-temp4)就是阳历日期距离下一年春节的天数,这时获取阴历从腊月开始从后向前计算的逐个月份的天数与(temp3-temp4)比较,就会得到阴历的月份和阴历的日期。在这期间也会包含对闰月的处理。

conversion函数参数解释:c为世纪标志,2000年以后c=0;2000年之前c=1。year位年份的后两位,如40。如果c为1表示1940.如果c为0表示2040.month为月份,day为日期。

*/
void Conversion(char c,char year,char month,char day)
{    
/*
temp1,temp2,temp3,temp4作为变量使用,month_p作为月份的指向,leap保存是否是闰年的数据,table_addr保存相关年份的year_code中的地址信息。flag_y是在处理闰月时的标志。
*/                     
    char temp1,temp2,temp3,month_p;
    int  leap,temp4,table_addr;
    char flag_y;
    //定位year_code数据表地址,也就是找到阴历的数据信息。如输入的是1988年,则找到1988年的阴历数据。
    if(c==0){    //如果是2000年以后               
        table_addr=(year+0x64-1)*0x3;
    }
    else {    //如果是2000以前
        table_addr=(year-1)*0x3;
    }
    //定位数据表地址完成,现在table_addr中存放的是阴历数据的第一个字节的地址。

    //取当年春节所在的公历月份
    temp1=year_code[table_addr+2]&0x60; //只获取第三个字节的位6至位5,其他位清零。
    temp1=temp1/32;            //右移五位,右移后temp1就是当年春节所在的公历月份
    //取当年春节所在的公历月份完成

    //取当年春节所在的公历日
    temp2=year_code[table_addr+2]&0x1f; //只获取第三个字节的位5至位0
    //取当年春节所在的公历日完成

    // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月
    if(temp1==0x1){      //春节在一月
        temp3=temp2-1;  
    }  
    else{        //春节在二月,需要加上一月的31天
        temp3=temp2+31-1;        
    }
    // 计算当年春年离当年元旦的天数完成



    //计算阳历日期离当年元旦的天数
/*
算法示例:假设输入的是1988年3月5日。那么首先判断是否是闰年,然后计算3月之前月份的天数和,最后加上3月的5天减1,(1月份总天数)+(2月份总天数)+(3月份天数)得到 31+29+5=63
*/
    //判断是否是闰年,闰年leap=1,非闰年leap=0
    leap=(year+1900)%4==0&&(year+1900)%100!=0||(year+1900)%400==0;
    temp4=0;    //保存天数
    for(c=1;c<month;++c)
        temp4=temp4+day_code[leap][c];
    temp4 = temp4+day;
    //计算阳历日期离当年元旦的天数完成

    //判断阳历日期在春节前还是春节后
    if (temp4>=temp3) //阳历日期在春节后或就是春节当日使用下面代码进行运算
    {
        temp4-=temp3;//(阳历日期离元旦的天数)减去(春年离元旦的天数)等于(阳历日期离春节的天数)
        month=1;//month指示的月份,是真正的阴历月份
/*
month_p为月份指向,他的指向和month是有区别的,month_p指向的是year_code中的阴历月份数据,month_p可能是13,因为如果闰月,阴历年就会有13个月。而month指向的是真正的阴历月份,如果闰5月month值就是5,阳历日期在春节后或就是春节当日month_p的初始值为1。
*/
        month_p=1;  
        flag_y=0;//flag_y是为了闰月设置的
        if(get_moon_day(month_p,table_addr)==0)//判断大小月
        temp1=29; //小月29天
        else
        temp1=30; //大月30天
        temp2=year_code[table_addr]&0xf0;//year_code的第一个字节的位7至位4为闰月月份
        temp2=temp2/16;  //右移四位,从数据表中取该年的闰月月份,如为0则该年无闰月
        while(temp4>=temp1){//如果阳历日期离春节的天数大于当前阴历月份的天数
            temp4-=temp1;
            month_p+=1;
/*
如果月份等于闰月月份,假设闰5月,那么阴历有两个5月,flag_y的作用就是保证第一次循环month的值不变,第二次循环month加1。从而保证计算两个5月。然而month_p的值加1两次,month_p的值可能达到13,既然闰月,这个阴历年就有13个月
*/
            if(month==temp2)
        {
                flag_y=~flag_y;
                if(flag_y==0)month+=1;
            }
            else
        month+=1;
            if(get_moon_day(month_p,table_addr)==0)//判断大小月
        temp1=29;
            else
        temp1=30;
        }
        day=temp4;
    }
    else  //阳历日期在春节前使用下面代码进行运算
    {
        temp3-=temp4;
    //阳历日期在春节前则阴历年减1
        if (year==0)//如果是2000年则变为1999年
        year=99;
        else
        year -= 1;//如果不是2000年则年数减1
        table_addr-=3;//同时改变table_addr的地址信息
        month=12;//阳历日期在春节前month初始值12,从后向前计算
        temp2=year_code[table_addr]&0xf0;//year_code的第一个字节的位7至位4为闰月月份
        temp2=temp2/16;//右移四位,从数据表中取该年的闰月月份,如为0则该年无闰月
    //month_p为月份指向,如果当年有闰月,一年有13个月,月指向13,无闰月指向12
        if (temp2==0)
        month_p=12;
        else
        month_p=13;
        flag_y=0;
        if(get_moon_day(month_p,table_addr)==0)//判断大小月
        temp1=29;
        else
        temp1=30;
        while(temp3>temp1)//如果阳历日期离春节的天数大于当前阴历月份的天数
    {
            temp3-=temp1;
            month_p-=1;
            if(flag_y==0)
        month-=1;
            if(month==temp2)
        flag_y=~flag_y;//flag_y的作用同上,保证闰月是month的值两次循环只改变一次值。
            if(get_moon_day(month_p,table_addr)==0)
        temp1=29;
            else
        temp1=30;
         }
        day=temp1-temp3;//由于是从后向前计算所以当月的天数减去剩余的天数就是日期
    }
//将计算后的数据,保存到全局变量
glo_year=year+1900;
glo_month=month;
glo_day=day;
}

/*
阴历转阳历

阴历转阳历的算法如下:
根据阴历数据year_code可以获得春节在当年的阳历日期(春节只会在当年的阳历1月或2月份)-->
根据春节的阳历日期可以得到春节距离元旦的天数(temp3)-->
然后计算需要转换的阴历日期距离春节的天数(temp4),(temp4+temp3)就是阴历日期距离元旦的天数-->
(temp3+temp4)与365(闰年366)比较就会得出需要转换的阴历日期是在今年还是明年(作此比较是因为阴历的12月份会是阳历第二年的1月或2月份)

*/
void Conversion_2(char c,char year,char month,char day)
{                     
    char temp1,temp2,temp3,month_p;
    int  i,temp4,leap,table_addr;
    char flag_y;


    //定位year_code数据表地址,也就是找到阴历的数据信息。如输入的是1988年,则找到1988年的阴历数据。
    if(c==0){                   
        table_addr=(year+0x64-1)*0x3;
    }
    else {
        table_addr=(year-1)*0x3;
    }
    //定位数据表地址完成

    //取当年春节所在的公历月份
    temp1=year_code[table_addr+2]&0x60;
    temp1=temp1/32;
    //取当年春节所在的公历月份完成

    //取当年春节所在的公历日
    temp2=year_code[table_addr+2]&0x1f;
    //取当年春节所在的公历日完成

    // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月
    if(temp1==0x1){  
        temp3=temp2-1;  
    }  
    else{
        temp3=temp2+0x1f-1;        
    }
    // 计算当年春年离当年元旦的天数完成

    //计算阴历日离当年元旦的天数
    i=0x1;            
    month_p=0x1;
        temp4=0;
    flag_y=0;
    if(get_moon_day(month_p,table_addr)==0)
        temp1=29; //小月29天
        else
        temp1=30; //大小30天
    //temp2闰月月份
        temp2=year_code[table_addr]&0xf0;
        temp2=temp2/16;
    while(i<month)
    {
    temp4 += temp1;        
        month_p += 1;
        if(i==temp2){
            flag_y=~flag_y;
            if(flag_y==0)
                i += 1;
        }
        else i += 1;
            if(get_moon_day(month_p,table_addr)==0)
        temp1=29;
            else
        temp1=30;
    }
    temp4=leap =temp4 + day + temp3;

    //计算阴历日期离当年元旦的天数完成

    //判断阴历日期在阳历今年还是明年
    leap=(year+1900)%4==0&&(year+1900)%100!=0||(year+1900)%400==0;//判断是否闰年
    if(leap==1)//如果闰年
    {
        if((temp4-366)>=0)//判断阴历日期在阳历今年还是明年,如果是阳历的下一年
        {
            year +=1;//年数加一
            temp4=temp4-366;//距离下一年元旦的天数
            //判断下一年是否是闰年
            leap=(year+1900)%4==0&&(year+1900)%100!=0||(year+1900)%400==0;
            month=1;
            //因为是阴历12月的话,只可能是下一年的阳历1月或2月份,所以比较一次
            if(temp4>=31)
            {
                month += 1;
                temp4=temp4-31;
            }
        }
        else//如果阴历的日期和阳历的日期属于同一年
        {
            //调用阳历各个月份的数据进行计算
            for(i=1;temp4>day_code[leap][i];i++)
                temp4 -= day_code[leap][i];
        month=i;
        }
    }
    else
    {
        if((temp4-365)>=0)//非闰年
        {
            year +=1;
            temp4=temp4-365;
            leap=(year+1900)%4==0&&(year+1900)%100!=0||(year+1900)%400==0;
            month=1;
            if(temp4>=31)
            {
                month += 1;
                temp4=temp4-31;
            }
        }
        else
        {
            for(i=1;temp4>day_code[leap][i];i++)
                temp4 -= day_code[leap][i];
        month=i;
        }
    }
//将计算后的数据,保存到全局变量
glo_year=year+1900;
glo_month=month;
glo_day=temp4;
}

//输入日期信息,含错误处理
int input_date(int *c,int *temp1,int *year,int *month,int *day)
{
    int temp;
    printf("输入的是阳历还是阴历,阳历输入1,阴历输入0.\n");
    scanf("%d",temp1);
    if(*temp1<0 || *temp1>1)
        return 1;
    
    printf("输入日期:年 月 日\n");
    scanf("%d %d %d",year,month,day);
    if(*year<1901||*year>2049)
        return 1;
    temp=*year/100;
    if(temp==19)
        *c=1;
    else
        *c=0;
    if(*month<1 || *month>12)
        return 1;
    if(*day<=0 || *day>31)
        return 1;
    return 0;
}

int main(){
    int temp1,c,year,month,day;

    
    while((input_date(&c,&temp1,&year,&month,&day))==1)
        printf("输入有误请重新输入\n");
    if(temp1==1){
        printf("阳历:%d    %d    %d\n",year,month,day);
        Conversion(c,year%100,month,day);
        printf("阴历:%d    %d    %d\n",glo_year,glo_month,glo_day);
    }
    else{
        printf("阴历:%d    %d    %d\n",year,month,day);
        Conversion_2(c,year%100,month,day);
        printf("阳历:%d    %d    %d\n",glo_year,glo_month,glo_day);
    }

}

//参考文献:http://blog.youkuaiyun.com/lengshine/archive/2010/04/10/5470616.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值