#include <stdio.h>
/*
下面是公历年对应的农历年数据,每年三字节,数据格式为:
第一字节位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);
}
//lingbofeiyun
//email:charlay_yu@163.com
/*
下面是公历年对应的农历年数据,每年三字节,数据格式为:
第一字节位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