公历和农历转换算法详解
//C51写的公历转农历和星期
#define uchar unsigned char
#define uint unsigned int
#include
/*
公历年对应的农历数据,每年三字节,
格式第一字节BIT7-4 位表示闰月月份,值为0 为无闰月,BIT3-0 对应农历第1-4 月的大小第二字节BIT7-0 对应农历第5-12 月大小,第三字节BIT7 表示农历第13 个月大小
月份对应的位为1 表示本农历月大(30 天),为0 表示小(29 天)
第三字节BIT6-5 表示春节的公历月份,BIT4-0 表示春节的公历日期
*/
code uchar year_code[597] = {
0x04,0xAe,0x53, //1901 0
0x0A,0x57,0x48, //1902 3
0x55,0x26,0xBd, //1903 6
0x0d,0x26,0x50, //1904 9
0x0d,0x95,0x44, //1905 12
0x46,0xAA,0xB9, //1906 15
0x05,0x6A,0x4d, //1907 18
0x09,0xAd,0x42, //1908 21
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
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
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 294 0x0C,0x96,0x45, //2000 297 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
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 0x35,0x5B,0x37, //2050 0x09,0x37,0x4B, //2051 0x84,0x97,0xC1, //2052 0x04,0x97,0x53, //2053 0x06,0x4B,0x48, //2054 0x66,0xA5,0x3C, //2055 0x0e,0xA5,0x4f, //2056 0x06,0xB2,0x44, //2057 0x4A,0xB6,0x38, //2058 0x0A,0xAe,0x4C, //2059 0x09,0x2e,0x42, //2060
0x0C,0x96,0x49, //2062
0x7d,0x4A,0xBd, //2063
0x0d,0x4A,0x51, //2064
0x0d,0xA5,0x45, //2065
0x55,0xAA,0xBA, //2066
0x05,0x6A,0x4e, //2067
0x0A,0x6d,0x43, //2068
0x45,0x2e,0xB7, //2069
0x05,0x2d,0x4B, //2070
0x8A,0x95,0xBf, //2071
0x0A,0x95,0x53, //2072
0x0B,0x4A,0x47, //2073
0x6B,0x55,0x3B, //2074
0x0A,0xd5,0x4f, //2075
0x05,0x5A,0x45, //2076
0x4A,0x5d,0x38, //2077
0x0A,0x5B,0x4C, //2078
0x05,0x2B,0x42, //2079
0x3A,0x93,0xB6, //2080
0x06,0x93,0x49, //2081
0x77,0x29,0xBd, //2082
0x06,0xAA,0x51, //2083
0x0A,0xd5,0x46, //2084
0x54,0xdA,0xBA, //2085
0x04,0xB6,0x4e, //2086
0x0A,0x57,0x43, //2087
0x45,0x27,0x38, //2088
0x0d,0x26,0x4A, //2089
0x8e,0x93,0x3e, //2090
0x0d,0x52,0x52, //2091
0x0d,0xAA,0x47, //2092
0x66,0xB5,0x3B, //2093
0x05,0x6d,0x4f, //2094
0x04,0xAe,0x45, //2095
0x4A,0x4e,0xB9, //2096
0x0A,0x4d,0x4C, //2097
0x0d,0x15,0x41, //2098
0x2d,0x92,0xB5, //2099
};
///月份数据表
code uchar day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3}; code uint day_code2[3]={0x111,0x130,0x14e};
/*
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据*/
bit c_moon;
data uchar year_moon,month_moon,day_moon,week;
/*子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0*/
bit get_moon_day(uchar month_p,uint table_addr)
{
uchar 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);}
}
}
/*
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据*/
void Conversion(bit c,uchar year,uchar month,uchar day)
{ //c=0 为21世纪,c=1 为19世纪输入输出数据均为BCD数据uchar temp1,temp2,temp3,month_p;
uint temp4,table_addr;
bit flag2,flag_y;
temp1=year/16; //BCD->hex 先把数据转换为十六进制
temp2=year%16;
year=temp1*10+temp2;
temp1=month/16;
temp2=month%16;
month=temp1*10+temp2;
temp1=day/16;
temp2=day%16;
day=temp1*10+temp2;
//定位数据表地址
if(c==0)
{
table_addr=(year+0x64-1)*0x3;
}
else
{
table_addr=(year-1)*0x3;
}
//定位数据表地址完成
//取当年春节所在的公历月份
temp1=year_code[table_addr+2]&0x60;
temp1=_cror_(temp1,5);
//取当年春节所在的公历月份完成
//取当年春节所在的公历日
temp2=year_code[table_addr+2]&0x1f;
//取当年春节所在的公历日完成
// 计算当年春年离当年元旦的天数,春节只会在公历1月或2月
if(temp1==0x1)
{
temp3=temp2-1;
}
else
{
temp3=temp2+0x1f-1;
}
// 计算当年春年离当年元旦的天数完成
//计算公历日离当年元旦的天数,为了减少运算,用了两个表
//day_code1[9],day_code2[3]
//如果公历月在九月或前,天数会少于0xff,用表day_code1[9],
//在九月后,天数大于0xff,用表day_code2[3]
//如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1
//如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1
if (month<10)
{
temp4=day_code1[month-1]+day-1;
}
else
{
temp4=day_code2[month-10]+day-1;
}
if ((month>0x2)&&(year%0x4==0))
{ //如果公历月大于2月并且该年的2月为闰月,天数加1
temp4+=1;
}
//计算公历日离当年元旦的天数完成
//判断公历日在春节前还是春节后
if (temp4>=temp3)
{ //公历日在春节后或就是春节当日使用下面代码进行运算
temp4-=temp3;
month=0x1;
month_p=0x1; //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月flag2=get_moon_day(month_p,table_addr);
//检查该农历月为大小还是小月,大月返回1,小月返回0
flag_y=0;
if(flag2==0)temp1=0x1d; //小月29天
else temp1=0x1e; //大小30天
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0则该年无闰月
while(temp4>=temp1)
{
temp4-=temp1;
month_p+=1;
if(month==temp2)
{
flag_y=~flag_y;
if(flag_y==0)
month+=1;
}
else month+=1;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp4+1;
}
else
{ //公历日在春节前使用下面代码进行运算
temp3-=temp4;
if (year==0x0)
{
year=0x63;c=1;
}
else year-=1;
table_addr-=0x3;
month=0xc;
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4);
if (temp2==0)
month_p=0xc;
else
month_p=0xd; //
/*month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,无闰月指向12*/ flag_y=0;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
while(temp3>temp1)
{
temp3-=temp1;
month_p-=1;
if(flag_y==0)month-=1;
if(month==temp2)flag_y=~flag_y;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp1-temp3+1;
}
c_moon=c; //HEX->BCD ,运算结束后,把数据转换为BCD数据
temp1=year/10;
temp1=_crol_(temp1,4);
temp2=year%10;
year_moon=temp1|temp2;
temp1=month/10;
temp1=_crol_(temp1,4);
temp2=month%10;
month_moon=temp1|temp2;
temp1=day/10;
temp1=_crol_(temp1,4);
temp2=day%10;
day_moon=temp1|temp2;
}
/*函数功能:输入BCD阳历数据,输出BCD星期数据(只允许1901-2099年)
调用函数示例:Conver_week(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世纪,c_sun=1为19世纪
调用函数后,原有数据不变,读week得出阴历BCD数据
*/
code uchar table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
/*
算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期但如果是在
闰年又不到3 月份上述之和要减一天再除7
星期数为0
*/
void Conver_week(bit c,uchar year,uchar month,uchar day)
{//c=0 为21世纪,c=1 为19世纪输入输出数据均为BCD数据
uchar temp1,temp2;
temp1=year/16; //BCD->hex 先把数据转换为十六进制
temp2=year%16;
year=temp1*10+temp2;
temp1=month/16;
temp2=month%16;
month=temp1*10+temp2;
temp1=day/16;
temp2=day%16;
day=temp1*10+temp2;
if (c==0){year+=0x64;} //如果为21世纪,年份数加100
temp1=year/0x4; //所过闰年数只算1900年之后的
temp2=year+temp1;
temp2=temp2%0x7; //为节省资源,先进行一次取余,避免数大于0xff,避免使用整型数据temp2=temp2+day+table_week[month-1];
if (year%0x4==0&&month<3)temp2-=1;
week=temp2%0x7;
}
//test
uchar c_sun,year_sun,month_sun,day_sun;
void main()
{
c_sun=1;
year_sun=0x2;
month_sun=0x11;
day_sun=0x3;
Conver_week(c_sun,year_sun,month_sun,day_sun);
Conversion(c_sun,year_sun,month_sun,day_sun);
while(1);
}
算法一:公历转农历
============================================================================ /*------------农历转换函数-----------*/
char *GetDayOf(PSYSTEMTIME pSt)
{
/*天干名称*/
const char *cTianGan[] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
/*地支名称*/
const char *cDiZhi[] = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
/*属相名称*/
const char *cShuXiang[] = {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};
/*农历日期名*/
const char *cDayName[] = {"*","初一","初二","初三","初四","初五",
"初六","初七","初八","初九","初十","十一","十二","十三","十四","十五","十六","十","十八","十九","二十","廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"};
/*农历月份名*/
const char *cMonName[] = {"*","正","二","三","四","五","六","七","八","九","十","十一","腊"};
/*公历每月前面的天数*/
const int wMonthAdd[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
/*农历数据*/
const int wNongliData[100] = {2635,333387,1701,1748,267701,694,2391,133423,1175,396438 ,3402,3749,331177,1453,694,201326,2350,465197,3221,3402
,400202,2901,1386,267611,605,2349,137515,2709,464533,1738
,2901,330421,1242,2651,199255,1323,529706,3733,1706,398762
,2741,1206,267438,2647,1318,204070,3477,461653,1386,2413
,330077,1197,2637,268877,3365,531109,2900,2922,398042,2395
,1179,267415,2635,661067,1701,1748,398772,2742,2391,330031
,1175,1611,200010,3749,527717,1452,2742,332397,2350,3222
,268949,3402,3493,133973,1386,464219,605,2349,334123,2709
,2890,267946,2773,592565,1210,2651,395863,1323,2707,265877};
static int wCurY ear,wCurMonth,wCurDay;
static int nTheDate,nIsEnd,m,k,n,i,nBit;
TCHAR szNongli[30], szNongliDay[10],szShuXiang[10];
/*---取当前公历年、月、日---*/
wCurY ear = pSt->wY ear;
wCurMonth = pSt->wMonth;
wCurDay = pSt->wDay;
/*---计算到初始时间1921年2月8日的天数:1921-2-8(正月初一)---*/
nTheDate = (wCurY ear - 1921) * 365 + (wCurY ear - 1921) / 4 + wCurDay + wMonthAdd[wCurMonth - 1] - 38;
if((!(wCurY ear % 4)) && (wCurMonth > 2))
nTheDate = nTheDate + 1;
/*--计算农历天干、地支、月、日---*/
nIsEnd = 0;
m = 0;
while(nIsEnd != 1)
{
if(wNongliData[m] < 4095)
k = 11;
else
k = 12;
n = k;
while(n>=0)
{
//获取wNongliData(m)的第n个二进制位的值
nBit = wNongliData[m];
for(i=1;i nBit = nBit/2; nBit = nBit % 2; if (nTheDate <= (29 + nBit)) { nIsEnd = 1; break; } nTheDate = nTheDate - 29 - nBit; n = n - 1; } if(nIsEnd) break; m = m + 1; } wCurY ear = 1921 + m; wCurMonth = k - n + 1; wCurDay = nTheDate; if (k == 12) { if (wCurMonth == wNongliData[m] / 65536 + 1) wCurMonth = 1 - wCurMonth; else if (wCurMonth > wNongliData[m] / 65536 + 1) wCurMonth = wCurMonth - 1; } /*--生成农历天干、地支、属相==> wNongli--*/ wsprintf(szShuXiang,"%s",cShuXiang[((wCurY ear - 4) % 60) % 12]); wsprintf(szNongli,"%s(%s%s)年",szShuXiang,cTianGan[((wCurY ear - 4) % 60) % 10],cDiZhi[((wCurY ear - 4) % 60) % 12]); /*--生成农历月、日==> wNongliDay--*/ if (wCurMonth < 1) wsprintf(szNongliDay,"闰%s",cMonName[-1 * wCurMonth]); else strcpy(szNongliDay,cMonName[wCurMonth]); strcat(szNongliDay,"月"); strcat(szNongliDay,cDayName[wCurDay]); return strcat(szNongli,szNongliDay); } ============================================================================ 首先,我们要确定一个时刻,作为一天的起点(包括这个时刻)。然后我们以月亮通过朔望交界点的那一天作为每个月的第一天,以太阳通过雨水点的那个月作为正月,依次的,以太阳通过各中气点的那个月作为二月、三月等等。 经过长期的观察之后,我们就会发现每个月不是29天就是30天,每年不是12个月就是13个月,每个中气点唯一对应一个月,但是有的月却没有中气。 为了制定我们的历法,我们至少要知道足够精度的朔望月长度,记为ML,和两个中气的间隔时间记为YL,这两个值经过前人长期不懈的观测和计算,我们知道分别为29.5306日和30.4377日。接下来,我们要随便找到某一年,以太阳通过雨水点的时刻到那一年开始的那个时刻的时间,记为DY,以日为单位,还要找出这一年正月里,月亮通过朔望交界点的时刻到那一月开始的那个时刻的时间,记为DM,以日为单位。这两个值是要通过实地观测得出来的。 这个时候,我们就可以通过递推来制订我们的历法,以预测未来月球和太阳的运行情况,并进一步预测月相的变化和气候的变化。 在本算法中我们使用了三个近似处理: 每天的长度总是一样的; 每个朔望月的长度总是一样的; 每两个相邻中气的时间总是一样的。 接下来,我们就逐月推算每月的大小: Select Case Fix(DM + ML) Case is = 29 The month have 29 days. The DM of next month is DM + ML - 29. Case is = 30 The month have 30 days. The DM of next month is DM + ML - 30. End Select 每年中各月的月份、是否为闰月 For i = 1 to 12 This month has A days. If DY>=A Then This month is an Extra Month. DY = DY - A Else This month is the i Month. DY = DY + YL - A i = i + 1 End If Next 这就是我们的核心算法。通过它,我们可以从任何一个包含中气的月份开始向后推算各月各年的情况。 由于我们所用的DM、DY、ML、YL都是近似值,若干年后,我们的历法必有偏差,我们只要重新观测,更新DM、DY、ML、YL的值就可以了。事实上,诸朝气数最多不过400年,在这些值精确到万分位的时候,通行一朝是完全可以的。 下面对大小月的排列和闰月的出现作一些定性分析 显然0≤DM<1,那么 DM<0.4694时,当月为小月,下月为大月 DM≥0.4694时,当月为大月 DM<0.4694 * 2时,下月为小月,下下月为大月 DM≥0.4694 * 2时,下月亦为大月,下下月为小月 所以,大小月一般是交替出现,有时会出现连续两个月是大月的情况,但不会出现连续三个月或更多的是大月的情况,也不会出现连续两个月更多的是小月的情况。也就是说,一般是小月大月相继出现一段时间后,接着就出现一个大月,然后又是小月大月相继出现,具体的间隔也不定,大家可以通过计算机推算后,找点规律出来。 一年中最少有十二个月,因为YL * 12 (代表十二个中气循环一次的时间)>ML * 12 (代表十二个朔望月的时间)+ 1 (第一个月的DM总小于1),最多有十三个月,因为30(第一个月的DY 总小于30)+ YL * 12 <ML * 14。两个相邻中气的间隔时间大于30,所以一个月不可能有两个中气,那么一年有十二个月的时候,12个中气必然刚好依次各居一个月,这一年就称为平年,一年有十三个月的时候,必然有且仅有一个月没有中气,那个月就时闰月,这一年就称为闰年。平年的时候,根据大小月的排列规则,一年最多有8个大月,最少有6个大月,因为ML * 12 + 1 <30 * 8 + 29 * (12 - 8),所以不可能有8个大月,最多为7个大月,那么一年就为354或355天。闰年的时候,根据大小月的排列规则,一年最多有9个大月,最少有6个大月,因为ML * 13 + 1 <30 * 8 + 29 * (13 - 8),所以不可能有8个或更多的大月,最多为7个大月,那么一年就为383或384天。 因为每月的天数不固定,所以闰月的出现规律也不好讨论,连续十二个月的天数也不固定,所以闰年的出现规律也不好讨论。不过可以肯定是,每年的第一个月肯定不是闰月,因为我们是以包含中气雨水的月份作为正月,也就是每年的第一个月的。所以,闰月必定出现在某个有名字的月份后面,出现在哪个后面就叫闰哪月。 由于有闰月,所以函数形式: int toSolar(int ly, int lm, int ld, int *sy, int *sm, int *sd, int *sy2, int *sm2, int *sd2); 引理:公历y-m-d一定在农历y-m-d之前 由引理,我们的探测可以从公历y-m-d开始,步骤如下: 1)toLunar(y, m, d, &ly0, &lm0, &ld0); 2)估算ly0-lm0-ld0和ly-lm-ld的日子差N = (ly-ly0)*12*29 + (lm-lm0)*29 + (ld-ld0); 3)如果N > 0,把探测公历y-m-d加上这个天数,dateAddDays(&y, &m, &d, N); 4)如果N = 0,如果(ly==ly0)&&(lm==lm0)&&(ld==ld0)得到一个解sy=y;sm=m;sd=d; (如果此时sy已经被赋值过,则sy2=y;sm2=m;sd2=d;返回退出) 否则表示出现误差,修正N = 1;dateAddDays(&y, &m, &d, N); 从而开始探测闰月,令N = 30;dateAddDays(&y, &m, &d, N); 5)如果N < 0,且N >= -30,肯定是上次探测N+29不够(该月大),应该+30, 所以令N = 1; dateAddDays(&y, &m, &d, N); 经过测试,最多需要3次可以命中,还是比较理想的算法了:) PS:经过完全测试,公元1500-2100年没有问,最多尝试次数为3次 #define LUNAR_TO_SOLAR_STEPS 3 // 公历转公历搜索最长步数 // 农历返回公历 // 注意:这是我在掌心万年历中写的代码,版权属于我所有,仅供个人学习使用,严禁在任何商业软件中使用本代码 // 输入农历年-月-日ly-lm-ld (lm < 0表示闰月) // 输出公历年-月-日y-m-d /* 公元1500年前的情况太特殊,比如公元9-1月,缺少农历11月,直接导致计算ldiff错误... 所以toSolar只支持1500年以后的转换. --ZV */ int toSolar(int LunarY ear, int LunarMonth, int LunarDay) { if (LunarY ear < 1500) { // 非常复杂的问题 return CALENDAR_ERROR; } int ret; int y = LunarY ear; int m = abs(LunarMonth); int d = LunarDay; int i, ldiff = 0, lunDate; int ly, lm, ld; validateDate(&y, &m, &d); for (i = 0; i < LUNAR_TO_SOLAR_STEPS; i++) { lunDate = toLunar(y, m, d); DA TE_TO_YMD(lunDate, ly, lm, ld); if (abs(lm) == abs(LunarMonth) && ld == LunarDay) { if (lm == LunarMonth) { ret = YMD_TO_DA TE(y, m, d); return ret; } // 如果找到一个,则开始探测闰月 ldiff = 30; // 要么直接转到,要么多了一天而已 } else { ldiff = (LunarY ear - ly) * 12 * 29 + (abs(LunarMonth) - abs(lm)) * 29 + (LunarDay - ld); if (ldiff == 0) { // 稍做修正 ldiff = 1; } } dateAddDays(&y, &m, &d, ldiff); // 注意可能出现负数} return CALENDAR_ERROR; } 阳历转化成农历法 ————————————————————————————————作者:————————————————————————————————日期: c++中怎样将阳历转化成农历 已关闭20[ 标签:c++, 阳历, 农历 ] 小^鱼、2011-05-03 11:06 推荐答案 一、原理篇 1.公历转换农历的算法 公历(Gregorian Calendar)与农历(Chinese Lunar Calendar)的转换关系不是一个简单的公式就可以完成,其中的转换比较复杂,原因是农历的制定相当复杂,是根据天文观测进行指定的。 比较常用并且比较简单的公历转换农历算法就是查表方法。首先要保存公历农历的转换信息:以任何一年作为起点,把从这一年起若干年的农历信息保存起来(在我的C++类中,是从1900年作为起点的。选择一个起始点的思想十分重要,在下面的干支纪法和二十四节气中也体现到了)。回想一下,我们平时是怎样来转换公历农历的呢?是查阅历书,历书中有每一天的公历农历,直接一查就可以了。那么我们可不可以也这样做呢?当然可以,但是这样做要收录每一天的信息,工作量就会很大,所以我们要简化这些信息。如何简化呢? 要保存一年的信息,其实只要两个信息就可以了:(1)农历每个月的大小;(2)今年是否有闰月,闰几月以及闰月的大小。用一个整数来保存这些信息就足够了。具体的方法是:用一位来表示一个月的大小,大月记为1,小月记为0,这样就用掉了12位,再用低四位来表示闰月的月份,没有闰月记为0。比如说,2000年的信息数据是0x0c960,转化成二进制就是1100100101100000,表示的含义是1、2、5、8、10、11月大,其余月小,低四位为0说明没有闰月。2001年的农历信息数据是0x0d954,其中的4表示该年闰4月,月份大小信息就是0x0d95,具体的就是1、2、4、5、8、10、12月大,其余月小。这样就可以用一个数组来保存这些信息。在我的C++类中是用m_lunarInfo这个数组来保存这些信息的。 下面就是公历转换成农历的具体算法: (1)计算所求时间到起始年正月初一的天数。 (2)从起始年份开始,减去每一月的天数,一直到剩余天数没有下一个月多为止。此时,m_lunarInfo的下标到了多少,就是减去了多少年,用起始年份加上这个下标就可以得到农历年份,然后看减去了几个月。如果本年不闰月或者闰月还在后面,就可以直接得到农历月份,如果在闰月月份数后面一个月,则这个月就是闰月。剩余的天数就是农历日。(具体实现时有所改进。) 2.利于泰勒公式巧算星期 在应用数学中有一个计算某一天是星期几的公式,这就是泰勒公式。公式如下: w = [c÷4] - 2c + y + [y÷4] + [26(m+1)÷10] + d - 1,其中w就是所求日期的星期数。如果求得的数大于(小于)7,就减去(加上)7的倍数,直到余数小于7为止。式子中c是指公 公历和农历之间如何转换? 很多人都一直在找换阴阳历的公式。我也尝试过。曾读过「高平子」天文前辈所着「学历散论」了解古历的变更和阴阳历的缺陷。才知道由於月球转动的不稳定不规则,确定无公式可寻。这也是古代中国每百年必改历的原因。 阴历最大的问题是在如何置闰。好像不难,因为阴历基本法则如下: * 月朔日即是初一 * 月以中气得名 * 以包含雨水中气月为正月,即是「寅」月 * 月无中气者为闰月,以前月同名 如果,日月转动循还有规则的话,推演一套阴阳历转换的公式并不难。问题在有时一个太阴月比一个太阳月还要长。如此一个太阴月就有可能包括两个中气。此双中气月後的阴历月名就全部乱掉了,直到下一个「假」闰月後才调整过来。 一般人接触到的阴阳历是民用历法,它是政府颁令的以东经120度计算的历法或称中原标准时间或北京时。如果,我们用不同时区、不同经度为子午线来重新计算阴阳历,民用历法的置闰法则出了很大的问题。不同时区的闰月可能落在不同月。换言之,在一百年内,任何两个时区的闰月顺序模式是会不相同的。 高平子前辈书中提到了「历理置闰法」。如果应用历理置闰法到不同时区,则所有不同时区的闰月都落在相同月。如此不同时区、不同经度的阴 阳历置闰之问题就消失了。民用置闰和历理置闰的不同是: * 在民用置闰,如果月朔日和中气同一天,则该阴历月包含那个中气。 * 在历理置闰,如果月朔日和中气同一天,月朔日时间必须在中气时间之前,则该阴历月才包含那个中气。 简言之,民用置闰比较月朔和中气日期;历理置闰比较月朔和中气日期、时、分、秒。由此可知,没有精确的太阳和月亮的时间数字,阴历的闰月可能会排错了。 基於这些理由,我着手寻找天文公式计算精确的太阳和月亮在纬度的时间。当年没有网路,发了大半年於美国南加州各大图书馆及大学,找寻答案。1993年出版了「中美天文万年历」一书。书中精确的天文日月时间只从1900到2010年。因恐2011後时间误差超过一分钟,不够精确,不敢印出。今年2002从网路资讯,确定太阳和月亮时间的精确度後,百忙中重新整理资料,提供给需要阴阳历转换公式的朋友。 整理出的太阳和月亮时间数字是从西元1年到2246年。有历理和中国民用两套历法。数字内容清清楚楚的看出民用历法的敝端。例如,从西元1600年到2246年,民用历法双中气的阴历月有22个,历理历法只有5个。民用历法甚至在2033、2128和2242年中,三个月之间居然跑出两个双中气;换言之,三个月中多出两个「假」闰月。前後12个阴历月中有三个闰月,闰月的去留造成许多学者的讨论和困恼。历理历法在此三年中,却没有发现到双中气阴历月。闰月的去留只要把双中气月後的「假」闰月取消,则历理历法近乎於完美。 由此可知,民用历法问题很大,应该废除。上次阴阳历重大改历在1645 公历和农历转换算法详解 //C51写的公历转农历和星期 #define uchar unsigned char #define uint unsigned int #include Public Function NongLi(Optional XX_DATE As Date) Dim MonthAdd(11), NongliData(99), TianGan(9), DiZhi(11), ShuXiang(11), DayName(30), MonName(12) Dim curTime, curYear, curMonth, curDay Dim GongliStr, NongliStr, NongliDayStr Dim i, m, n, k, isEnd, bit, TheDate '??è?μ±?°?μí3ê±?? curTime = XX_DATE 'ìì?é??3? TianGan(0) = "?×" TianGan(1) = "òò" TianGan(2) = "±?" TianGan(3) = "??" TianGan(4) = "?ì" TianGan(5) = "?o" TianGan(6) = "?y" TianGan(7) = "Dá" TianGan(8) = "èé" TianGan(9) = "1?" 'μ??§??3? DiZhi(0) = "×ó" DiZhi(1) = "3ó" DiZhi(2) = "òú" DiZhi(3) = "??" DiZhi(4) = "3?" DiZhi(5) = "?è" DiZhi(6) = "??" DiZhi(7) = "?′" DiZhi(8) = "éê" DiZhi(9) = "ó?" DiZhi(10) = "D?" DiZhi(11) = "o¥" 'ê??à??3? ShuXiang(0) = "êó" ShuXiang(1) = "?£" ShuXiang(2) = "?¢" ShuXiang(3) = "í?" ShuXiang(4) = "áú" ShuXiang(5) = "é?" ShuXiang(6) = "?í" 1、阳历日期推算阴历日期的方法: 前已述及阴历日期是以月亮的圆缺为计月单位,其以逢朔为初一,以月望为十五(大月 为十六日),以月晦为二十九日(大月为三十日)。 如要知道1984年6月8日是阴历几日?可以利用公式推算阴历日期: 设:公元年数-1977(或1901)=4Q+R 则:阴历日期=14Q+10.6(R+1)+年内日期序数-29.5n (注:式中Q、R、n均为自然数,R<4) 例:1994年5月7日的阴历日期为: 1994-1977=17=4×4+1 故:Q=4,R=1 则:5月7日的阴历日期为: 14×4+10.6(1+1)+(31+28+31+31+7)-29.5n =204.2- 29.5n 然后用29.5去除204.2得商数 6......27.2,6即是n值,余数27即是阴历二十七日2.公历换算为农历 二十四节气在黄道上的位置是固定的,但各年有平年和闰年之分,就使得回归年天数与 实际天数不等,每年在日历上可差一天。这样可以将阴历经过任意整回归年在现在的日历上 查到阳历(阳历一年相当阴历的月数为365.2422/29.530588=12.36827个月)。例如,可先在1995年的日历上查得与(该年)阴历对应的阳历日期,这样就找到了临时落脚点, 也就是找到了阴阳互换的关键。例如,可先以阴历四月初一(日)为引数,在1995年日历上查到对应的阳历为4月30日。由于已经计算出经过的月数,将经过的月数的尾数(小数)化为日,加在4月30日上,就得到经过(1995-1070)整年数的阳历日期,也就是起始阴 历日期对应的阳历日期,即得到了待查的日期为4月30日加上0.64957×29.530588得到(1070年)5月19.1821840日。这样就得到了所给例子的阴阳历日期换算结果……”。 0.64957月的由来, (1995-1070)×12.36827=11440.64957月 已知依泽公生于梁龙德二年(922)六月二十一日,依下表提供的2099年各月初一日的公历月日数,可以算出龙德二年六月二十一日的公历月日数 公元2099年农历各月初一日的公历月日 (2099-922)×12.36827=1455.45379月 余数为0.45379月×29.530588日=13.4O日 因2099年五月初一日(包括该年闯二月)在公历6月19日,加上计算所得的13日为龙德二年六月初一日的公历月日,即该年7月2日,则该年农历六月二十一日为该年7月22日。 3.计算结果的订正 实际上上列公历换算为农历时常有较大的误差,如熙宁三年四月初一日为公历1070年5月13日,而不是5月19日。通过中国历法所用的于支记日法求算所用两历的干支,对所 求结果加以订正。 如,马依泽公生于回历310年3月20日,自回历历元起算共历日数为: 自回历元旦至其3月20日,共历79日。 自回历元年元旦至309年元旦,共历113个闰年196个平年。又回历历元在公历622年7月16日,已知该日的干支序数为50,癸丑日,减1(因自甲子起算),余49应加入下列算式中, (309 ×354+113+79+49)÷60=1827.116667 excel公历转农历的四种方法 excel公历转农历方法一:使用text函数 A列是公历日期,我们在B1单元格输入公式:=TEXT(A1,"[$-130000]yyyy年m月"&I F(LEN(--TEXT(A1,"[$-130000]dd"))=1,"初","")&"d"),下拉完成公历转农历。 excel公历转农历方法二:使用text+MID函数 A列仍然是公历,B1输入公式:=MID("甲乙丙丁戊己庚辛壬癸",MOD(TEXT(A1,"[$-13 0000]e")-4,10)+1,1)&MID("子丑寅卯辰巳午未申酉戌亥",MOD(TEXT(A1,"[$-130000]e")-4, 12)+1,1)&"年"&TEXT(A1,"[$-130000][DBNum1]m月d日"即可。 excel公历转农历方法三:使用text+MID+ CHOOSE+ YEAR函数 A1为公历,B1输入:=CHOOSE(MOD(YEAR(A1)-1900,10)+1,"庚","辛","壬","癸","甲", "乙","丙","丁","戊","己")&CHOOSE(MOD(YEAR(A1)-1900,12)+1,"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥")&TEXT(A1,"[dbnum1][$-130000]年m月"&IF(--TEXT(A1, "[$-130000]d")<11,"初","")&TEXT(A1,"[dbnum1][$-130000]d")) excel公历转农历方法四:使用自定义函数 上面介绍的excel公历转农历都是使用excel内置函数完成的,有一个弊端就是公式太长,如果使用自定义函数,在公式栏就可以简化输入。 如下图所示,我们在B2输入公式:=nongli(A2),即可。C列农历简称中C2公式是:=RIGHT(B2,LEN(B2)-8)。 回历、公历、农历的换算 2002-2-10 22:02:19 马肇曾阅读9061次 研究世界伊斯兰教历史,免不了要对以回历所记载的历史事实换算为公历,或将所载的公历换算为回历。《回历纲要》、《历法丛谈》、《万年历谱》以及《回回天文学史研究》[1--4]等专著都载有自回历换算为公历的算式,并称两历因闰年的时间不同,故换算结果常有一日之差,惟均未讨论一日之差的简易订正方法。1998年《北京大学学报》(自然科学版)载文讨论了中国农历与公历、回历的换算问题[5]。惟笔者依上列著作中所列算式推算结果;发现与实际所载日期误差常大于一日,最高可达十日之多。因此有必要对计算中误差的来源及计算公式的改进进行探讨,特撰此文。 二、国历换算为公历 1.换算公式的导出 公历每年365.242 199074075 日(简化为365.2422日),而回历每年为354.367074375日(简化为354.36707日),所以回历一年只相当354.36707/365.2422=0.970223或0.970224个公历年。又回历元年元旦定在公元622年7月16日,由于当时历法在推算上的误差,致当时的7月16日,按现代的公历应改为7月19日,自公元某年元旦至该年7月19日已达200日.相200/365.2422=0.5476公历年;又因到回历二年元旦才达到0.970224个公历年,故自回历纪年元旦换算为公历的算式即为: (回历纪年一1)× 0.970224+622.5476年 =所求公历年月日 (1) 或回历纪年× 0.970224+621.5774年 =所求公历年月日 (2) 式中621.5774来自622.5476-0.970224。 如所求某一历史事实不在回历元旦时,可将事实经过本年的总日数化为回历年,加人回历纪年总数中即可。 然而上列公历一年的总日数,实际上是一回归年的实测数,因现用公历每年的日数实为365.2425日,它与一回归年的日数只能是基本相符,到公元四千多年后会再出现一日之差。 实际上在明万历十年九月十八日,回历990年9月16日,公元1582年10月4日前(包括4日)的公历称儒略历,儒略历每年365.25日,它每年与一回归年的差值远大于格列高利历即现代的公历,大约历128年就需多闰去一日,至万历十年已经多闰出十日了。因此,对于儒略历时期的回、公两历换算,不能仍采用(l)、(2)两式,而需依儒略历的年实际日数将上列二式略加修正即可,结果如下: (回历纪年一l)× 0.9702+622.5393 = 所求公历年月日 (3) c++中怎样将阳历转化成农历 已关闭20[ 标签:c++, 阳历, 农历 ] 小^鱼、2011-05-03 11:06 推荐答案 一、原理篇 1.公历转换农历的算法 公历(Gregorian Calendar)与农历(Chinese Lunar Calendar)的转换关系不是一个简单的公式就可以完成,其中的转换比较复杂,原因是农历的制定相当复杂,是根据天文观测进行指定的。 比较常用并且比较简单的公历转换农历算法就是查表方法。首先要保存公历农历的转换信息:以任何一年作为起点,把从这一年起若干年的农历信息保存起来(在我的C++类中,是从1900年作为起点的。选择一个起始点的思想十分重要,在下面的干支纪法和二十四节气中也体现到了)。回想一下,我们平时是怎样来转换公历农历的呢?是查阅历书,历书中有每一天的公历农历,直接一查就可以了。那么我们可不可以也这样做呢?当然可以,但是这样做要收录每一天的信息,工作量就会很大,所以我们要简化这些信息。如何简化呢? 要保存一年的信息,其实只要两个信息就可以了:(1)农历每个月的大小;(2)今年是否有闰月,闰几月以及闰月的大小。用一个整数来保存这些信息就足够了。具体的方法是:用一位来表示一个月的大小,大月记为1,小月记为0,这样就用掉了12位,再用低四位来表示闰月的月份,没有闰月记为0。比如说,2000年的信息数据是0x0c960,转化成二进制就是1100100101100000,表示的含义是1、2、5、8、10、11月大,其余月小,低四位为0说明没有闰月。2001年的农历信息数据是0x0d954,其中的4表示该年闰4月,月份大小信息就是0x0d95,具体的就是1、2、4、5、8、10、12月大,其余月小。这样就可以用一个数组来保存这些信息。在我的C++类中是用m_lunarInfo这个数组来保存这些信息的。 下面就是公历转换成农历的具体算法: (1)计算所求时间到起始年正月初一的天数。 (2)从起始年份开始,减去每一月的天数,一直到剩余天数没有下一个月多为止。此时,m_lunarInfo的下标到了多少,就是减去了多少年,用起始年份加上这个下标就可以得到农历年份,然后看减去了几个月。如果本年不闰月或者闰月还在后面,就可以直接得到农历月份,如果在闰月月份数后面一个月,则这个月就是闰月。剩余的天数就是农历日。(具体实现时有所改进。) 2.利于泰勒公式巧算星期 在应用数学中有一个计算某一天是星期几的公式,这就是泰勒公式。公式如下: w = [c÷4] - 2c + y + [y÷4] + [26(m+1)÷10] + d - 1,其中w就是所求日期的星期数。如果求得的数大于(小于)7,就减去(加上)7的倍数,直到余数小于7为止。式子中c是指公 公元与农历的换算方法 一、记住农历的天干和地支的顺序 天干顺序:甲、乙、丙、丁、戊、己、庚、辛、壬、癸。 地支顺序:子、丑、寅、卯、辰、巳、午、未、申、酉、戍、亥。 二、掌握天干和地支的搭配方法KCB齿轮泵 年数从甲子、乙丑、丙寅、丁卯、戊辰、己巳、庚午、辛未、癸酉;后继续甲戍、乙亥、丙子……,60年时刚好是葵亥。每个干支为一年,六十个干支后,又从头算起2CY系列齿轮泵,周而复始,循环不息。由甲子开始,满六十年称做一甲子或一花甲子,称为干支纪年法。搭配时先天干后地支。 三、使用如下公式KCB不锈钢齿轮泵 1、天干计算公式:(公元年代—3)/10.整除时是葵,余数1、 2、 3、 4、 5、 6、 7、 8、9分别是甲、乙、丙、丁、戊、己、庚、辛、壬(按顺序)。LYB系列立式液下齿轮泵 2、地支计算公式:(公元年代—3)/12.整除时是亥,余数1、2、 3、4、5、6、7、8、9、10、11分别是子、丑、寅、卯、辰、巳、午、未、申、酉、戍(按顺序)KCB-T铜齿轮泵。 如:1894年甲午中**战争 (1894—3)/10 余数是1,GZYB高精度齿轮泵天干属于“甲”;(1894—3)/12 余数是7,地支属于“午”。再把天干和地支合起来就是“甲午”。KCB系列大流量齿轮泵 又如:1898年戊戌变法 (1898—3)/10 余数是5,KCB齿轮泵安装尺寸天干属于“戊”;(1898—3)/12 余数是11,地支属于“戌”。再把天干和地支合起来就是“戊戌”。2CY齿轮泵安装尺寸 再如:1911年辛亥革命 (1911—3)/10 余数是8,天干属于“辛”;(1911—3)/12 结果是整除,地支属于“亥”。高压齿轮泵再把天干和地支合起来就是“辛亥”。 public class Date2 { //天干 private static string[] TianGan = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" }; //地支 private static string[] DiZhi = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" }; //十二生肖 private static string[] ShengXiao = { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" }; //农历日期 private static string[] DayName = {"*","初一","初二","初三","初四","初五", "初六","初七","初八","初九","初十", "十一","十二","十三","十四","十五", "十六","十七","十八","十九","二十", "廿一","廿二","廿三","廿四","廿五", "廿六","廿七","廿八","廿九","三十"}; //农历月份 private static string[] MonthName = { "*", "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊" }; //公历月计数天 private static int[] MonthAdd = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; //农历数据 private static int[] LunarData = {2635,333387,1701,1748,267701,694,2391,133423,1175,396438 ,3402,3749,331177,1453,694,201326,2350,465197,3221,3402 ,400202,2901,1386,267611,605,2349,137515,2709,464533,1738 ,2901,330421,1242,2651,199255,1323,529706,3733,1706,398762 ,2741,1206,267438,2647,1318,204070,3477,461653,1386,2413 ,330077,1197,2637,268877,3365,531109,2900,2922,398042,2395 ,1179,267415,2635,661067,1701,1748,398772,2742,2391,330031 ,1175,1611,200010,3749,527717,1452,2742,332397,2350,3222 ,268949,3402,3493,133973,1386,464219,605,2349,334123,2709 ,2890,267946,2773,592565,1210,2651,395863,1323,2707,265877}; 阳历日期推算阴历日期的方法:前已述及阴历日期是以月亮的圆缺为计月单位,其以逢朔为初一,以月望为十五(大月为十六日),以月晦为二十九日(大月为三十日)。然而目前记时通常用阳历日期表达,如欲将阳历日期换算成阴历日期可以用以下两种方法:其一是查《新编万年历》,如查1984年6月8日是阴历几日?翻开万年历6月10日是阴历十一,则逆推6月8日是阴历初九。其二可以利用公式推算阴历日期: 设:公元年数-1977(或1901)=4q+r 则:阴历日期=14q+10.6(r+1)+年内日期序数-29.5n (注:式中q、r、n均为自然数,r<4) 例:1994年5月7日的阴历日期为: 1994-1977=17=4×4+1 故:q=4,r=1 则:5月7日的阴历日期为: 14×4+10.6(1+1)+(31+28+31+31+7)-29.5n =204.2- 29.5n 然后用29.5去除204.2得商数6......27.2,6即是n值,余数27即是阴历二十七日。 蔡勒(Zeller)公式:是一个计算星期的公式。 随便给一个日期,就能用这个公式推算出是星期几。 蔡勒公式如下: W = [ C/4 ] - 2C + y + [ y/4 ] + [ 13 * (M + 1) / 5] + d -1 公式中的符号含义如下: W: 星期;w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六 C: 世纪-1(前两位数) y: 年(后两位数) m: 月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算) d: 日 [ ]代表取整,即只要整数部分。 下面以中华人民共和国成立100周年纪念日那天(2049年10月1日)来计算是星期几,过程如下: w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 =49+[49/4]+[20/4]-2×20+[26×(10+1)/10]+1-1 =49+[12.25]+5-40+[28.6] =49+12+5-40+28 =54 (除以7余5) 即2049年10月1日(100周年国庆)是星期五。 再比如计算2006年4月4日,过程如下: w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1 =6+[6/4]+[20/4]-2*20+[26*(4+1)/10]+4-1 =-12 (除以7余2,注意对负数的取模运算!) 不过,以上的公式都只适合于1582年(我国明朝万历十年)10月15日之后的情形。罗 公历转农历(A版本) Tags:版本wCurMonth wCurYear if农历nTheDate nBit const公历转农历(C 版本) PHP开发环境的选择、建立及使用[8]编写自定义任务,轻松扩展Ant(2)代联接的自定义右键菜单面试中如何体现身价希特勒生日(4月20日)突破生命中那条线怎么用ado打开带密码的access数据库算法复杂度攻击激烈讨论在Visual https://www.sodocs.net/doc/0811290874.html,中使用自定义插公历转农历(C版本)版本wCurMonth wCurYear if农历nTheDate nBit const 前段时间做软件写了个公历转农历的函数,目前公开给大家参考,有兴趣的朋友可以在此基础上进一步完善其功能 /*------------农历转换函数-----------*/ char *GetDayOf(PSYSTEMTIME pSt) { /*天干名称*/ const char *cTianGan[] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"}; /*地支名称*/ const char *cDiZhi[] = {"子","丑","寅","卯","辰","巳","午", "未","申","酉","戌","亥"}; /*属相名称*/ const char *cShuXiang[] = {"鼠","牛","虎","兔","龙","蛇", "马","羊","猴","鸡","狗","猪"}; /*农历日期名*/ const char *cDayName[] = {"*","初一","初二","初三","初四","初五", "初六","初七","初八","初九","初十", 采用查表的方法实现农历与公历的转换,可以坚持50年,50年以后可以补充表继续使用,当然50年以后什么样子都不知道,这个方法可能早淘汰了。哈哈! #define uchar unsigned char #define uint unsigned int #include 参看一: 可以这样试一下:EXCEL2007中可以直接做到,例如 TEXT(日期,"[$-130000]e-m-d"),可返回日期的阿拉伯数字的农历年月日, 中文农历转换公式如下: B2单元格 =MID("庚辛壬癸甲乙丙丁戊己",MOD(TEXT(A2,"[$-130000]e"),10)+1,1)&MID("申酉戌亥子丑寅卯辰巳午未",MOD(TEXT(A2,"[$-130000]e"),12)+1,1)&TEXT(A2,"[dbnum1][$-130000]年M月 "&IF(-TEXT(A2,"[$-130000]d")<-10,,"初")&"D日") 此公式仅EXCEL2007以使用,EXCEL2003及以下不能正常使用 上面那个公式好像有问题,可以试一下这个: 参看二: 日期在A2, 这个公式在B2 =CHOOSE(MOD(YEAR(LEFT(TEXT(A2,"[$-130000]yyyy年mm月"&IF(LEN(--TEXT(A2,"[$-130000]dd"))=1,"初","")&"dd"),4)&"-"&MID(TEXT(A2,"[$-130000]yyyy年mm月"&IF(LEN(--TEXT(A2,"[$-130000]dd"))=1,"初","")&"dd"),6,2)&"-"&RIGHT(TEXT(A2,"[$-130000]yyyy年mm月"&IF(LEN(--TEXT(A2,"[$-130000]dd"))=1,"初","")&"dd"),2))-1900,10)+1,"庚","辛","壬","癸","甲","乙","丙","丁","戊","己 ")&CHOOSE(MOD(YEAR(LEFT(TEXT(A2,"[$-130000]yyyy年mm月"&IF(LEN(--TEXT(A2,"[$-130000]dd"))=1,"初","")&"dd"),4)&"-"&MID(TEXT(A2,"[$-130000]yyyy年mm月"&IF(LEN(--TEXT(A2,"[$-130000]dd"))=1,"初","")&"dd"),6,2)&"-"&RIGHT(TEXT(A2,"[$-130000]yyyy年mm月"&IF(LEN(--TEXT(A2,"[$-130000]dd"))=1,"初","")&"dd"),2))-1900,12)+1,"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥 ")&TEXT(A2,"[dbnum1][$-130000]年m月"&IF(--TEXT(A2,"[$-130000]d")<11,"初 ","")&TEXT(A2,"[dbnum1][$-130000]d日")) =CHOOSE(MOD(YEAR(LEFT(TEXT(A11,"[$-130000]yyyy年mm月" &IF(LEN(--TEXT(A11,"[$-130000]dd"))=1,"初","") &"dd"),4) &"-"&MID(TEXT(A11,"[$-130000]yyyy年mm月" &IF(LEN(--TEXT(A11,"[$-130000]dd"))=1,"初","") &"dd"),6,2) &"-"&RIGHT(TEXT(A11,"[$-130000]yyyy年mm月" &IF(LEN(--TEXT(A11,"[$-130000]dd"))=1,"初","") &"dd"),2))-1900,10)+1,"庚","辛","壬","癸","甲","乙","丙","丁","戊","己") &CHOOSE(MOD(YEAR(LEFT(TEXT(A11,"[$-130000]yyyy年mm月" &IF(LEN(--TEXT(A11,"[$-130000]dd"))=1,"初","") &"dd"),4)&"-" &MID(TEXT(A11,"[$-130000]yyyy年mm月" &IF(LEN(--TEXT(A11,"[$-130000]dd"))=1,"初","") &"dd"),6,2) &"-" &RIGHT(TEXT(A11,"[$-130000]yyyy年mm月" &IF(LEN(--TEXT(A11,"[$-130000]dd"))=1,"初","") &"dd"),2))-1900,12)+1,"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥") 公历转换为农历的算法: 0101000101111 前12为代表大小月,第13位代表闰月的大小月 6 代表闰月的月份 0 代表无闰月 64311 代表当年春节的公历日期 1.首先获取当前日期。S time=+$h 2.判断查询日期是否在春节之前。如果是取上一年的信息。否则取当前年的信息为 农历年 3. 4.判断当前日期和最近的春节相差的天数。 Days 5.如果没有闰月,判断前12位的大小月, 如果是大月 ,则相差天数-30 如果是小月则相差天数-29,直到相差天数在30 或者 29天内。 取当前的月份,即农历的月份,天数+1 即为农历的天。 如果有闰月,判断前13位的大小月,判断方法和前面的类似,只是到闰月的月份时,需要在前面增加一个闰字。 /// gl 23/06/2016格式 gldays数字形式的日期 /// w ##class(websys.CalendarUtil).ToLuner("01/01/2017") /// @param: gl 公历日期格式 DD/MM/YYYY /// @return: 返回农历日期 2016*8*12 2017*闰6*12,2017*闰6*12 ClassMethod ToLuner(gl = {+$h}) { //q "2016*8*12" s Nmonth="" s Nday="" s ^TMP("Toluner")=$g(gl) if gl=""{ set gldt=$h set gldays=$p(gldt,",",1) set gl=$zd(gldays,4) }else{ set gldays=$zdh(gl,4) } ;获取传过来的年份 set year=$p(gl,"/",3) ;查询数据库,获取这个年份的信息串 set calId="" Set calId = $o(^websys.CalendarUtilI("YearIndex"," "_year,calId)) q:calId="" "" s g=$list(^websys.CalendarUtilD(calId),1,3) Set calInfo = $list(g,2) b ;获取这个信息串的春节 s springFes=$p(calInfo,"^",3) ;如果要查询的日期在春节之前,获取前一年的信息串 if (gldays 公历日期与农历日期的相互转换程序 //********************************** // 公历日期与农历日期的相互转换程序 // 公元1800年1月25日~2101年1月28日 // 请在VC++6.0平台运行 //********************************** #include; #include; #include; #include; #include; #include; struct date{ short year,month,day; } d1={ 1800,1,25 },//农历1800正月初一(星期六) d2={ 2101,1,28 };//农历2100腊月廿九(未使用) struct lunarYear //农历年 { char run; //闰月月份(0表示无闰月) char ZL[13]; //农历i月初一对应公历i月ZL[i]日(广义) } Year[2101 //但是ZL[i]的最高位1表示大月0表示小月 -1800]={4};//农历1800年闰四月 #define leap(y) !(y%(y%100?4:400)) //公元闰年宏定义 unsigned char days[]={ 0,31,28,31,30,31,30,31,31,30,31,30,31 }, b[]= //农历1800-2100年大月(30天)小月(29天)闰月数据(hex string) { "adca5aa92bb525bba25bb493b64a5ba9add496ea8a6 ed14eea4a6da5b6" "545baa4bba45bba82b75a5b654abaa55d526eda4aed 495da526daa5655" "abb295ba5257aa4b75a95655abaa56ea4a5da92ed96 5d594adaa56692b" "75a5ba64977493b6ca5a69add496da925dd24dda495 da9add45a6a4b75" 一.简单的历法知识 干支的推算和历法知识是密切相关的,因此大家首先应该对历法有所了解,若已具备相关知识,可跳过此部分。历法是以太阳、月亮、地球三者在运行时间上的关系,制定时间顺序的法则。现行的历法大致分为三类太阳历,太阴历,阴阳历, 1.“太阳历”就是我们所说的“阳历”,是以“回归年” (地球绕太阳运行一周的时间)为侧重点制定历法,首先规定一个“回归年”为一年,为365天,然后规定每年有12个月,1,3,5,7,8,10,12月为大月31天,其余月为30天,由于“回归年”的准确时间是365天5小时48分46秒,四年则与实际回归年差一天,因此每四年设一个“润年”366天。 2.“太阴历”并非我们所说的农历,他是以“朔望月”(月亮绕地球一周的时间)为侧重点,首先规定一个“朔望月”的时间为一个月,然后规定12个月为一年,一个“朔望月”大约为日,因此设大月为30天,小月29天,单月是大月,双月是小月。12个太阴历的月是354天,比回归年差不多短了11天。3年就短一个多月。所以使用这种历时,新年不一定在冬天过,它可以在春天过,也可以在夏天或秋天过。它的惟一好处就是阴历上的每一个日期都可以知道月亮的形状。当今世界上除了几个伊斯兰教国家因为宗教上的原因仍然使用外,其他国家一般已经废弃不用了。 3.“阴阳历”才是我们常说的农历,之所以叫“阴阳历”是因为他兼顾了“回归年”和“朔望月”两个时间特点,他同样是首先规定一个“朔望月”的时间为一个月,大月为30天,小月29天,但农历的大小月由推算决定,以“朔”(月亮不出现的日子)为每个月的初一,并使用“闰月”的办法解决太阴历的不足。为保证每月的头一天(初一)必须是朔日,就使得大小月的安排不固定,而需要通过严格的观测和计算来确定。 设置“润月”的目的是为了使m个回归年的天数与n个朔望月的天数相等,即 m×=n× (1)阳历转化成农历法
公历和农历之间如何转换
公历和农历转换算法详解
公历转农历EXCEL宏讲解
阴历阳历转换计算公式
excel公历转农历的四种方法
回历、公历、农历的换算
阳历转化成农历算法
公元与农历的换算方法
阳历与阴历的转换
公历转农历方法
公历转农历(a版本)
采用查表的方法实现农历与公历的转换)
Excel公历转农历阳历转阴历
公历转换为农历的算法
公历日期与农历日期的相互转换程序
阴历阳历转换算法2