1、摘自: 星期、干支、二十八宿计算公式 打印本页 关闭本窗口 1. 求星期公式星期=5+A(实际天数) mod 72. 干支计算公式六十甲子干支序号,从 1-59-0。六十甲子干支序号=23+A(实际天数) mod 603. 二十八宿计算公式二十八宿序号=23+A(实际天数) mod 284. 实际天数 A 的计算A=B(基本天数)+C(闰日天数)B=(计算年-1)*365+(要计算到年的月日天数 )例:1984 年 2 月 1 日的基本天数 B=(1984-1)*365+(31+1)=723827(天) ,其中,31 是 1 月为 31 天,1 为 2 月 1 日为 1 天。公元 308 年
2、8 月 28 日的基本天数B=(308-1)*365+(31+28+31+30+31+30+31+27)=112055+239=112294(天)这里的(要计算到年的月日天数 ),用的是公历,月日天数的规则我好象小学就学过了。哈哈C=(计算年-1) div 4 -误差修正值 + fixValue2fixValue2 为 0 或者 1。常值为 0,当年数为闰年(公历闰年法)之中的 3 月1 日之后的为 1。误差修正值推算:公元元年 1 月 1 日至 1582 年 10 月 14 日为 0。1582 年 10 月 15 日至 1699 年 12 月 31 日为 10。从 1701 年 1 月 1
3、日起每增加一个世纪累加 1,但能被 400 除尽的世纪不累加 1。此方法推算即可。-有一个问题,1700 年这一年的修正值应为多少呢?算法中正好没有讲到,但看来应该是 10。例 1701 年 1 月 1 日起误差值为 11,而 1801 年 1 月 1 日起误差修正值为 12,而 1901 年 1 月 1 日起误差修正值为 13,但 2001 年误差修正值仍为 13,因为 2000 年能被 400 整除,故不累加。而2101 年 1 月 1 日起误差修正值为 14。5. 实例:1998.3.15 的星期、干支与二十八宿B=(1998-1)*365+(31+28+15)=728979C=(199
4、8-1) div 4 - 13 + 0 = 486A=B+C=728979+486=729465星期序号=(5+729465) mod 7=0,即为星期日干支序号=(13+729465) mod 60=58,即为辛酉二十八宿序号=(23+729465) mod 28=4,即为房=好可怕!还有一些其它公式但好象有些参数不知道怎么得到:二十四节交节日算法:用已知年的交接时辰加上 22 个小时 35 分,超过 24 要减去 24,分数足 60进 1 个小时,即得到 8 年后的各节交节时辰。如 2000 年雨水交节时辰为 16 时 22 分,则 2008 年雨水交节时辰为 14 时 52分。因为 16
5、 时 22 分+22 时 35 分=38 时 57 分。38-24=14 时。谁知道公元元年到公元八年的交节日,这个算法就可以实现了。-好象逆算法可以解决这个问题。谁试试?农历闰月算法:农历中,二十四节气(十二节气和十二中气 )的中气落在月末的话,下个月就没有中气。农历将这种有节(节气) 无气(中气) 的月份规定为闰月。平均计算,19 年有七个闰月。但二十四个节气的十二节气和十二中气是怎么分的呢?我没有资料,估记应该是一节气一中气这样交叉。 :(unit CNYear; interface uses sysutils; type TCNDate = Cardinal; function Dec
6、odeGregToCNDate(dtGreg:TDateTime):TCNDate; function GetGregDateFromCN(cnYear,cnMonth,cnDay:word;bLeap:Boolean=False):TDateTime; function GregDateToCNStr(dtGreg:TDateTime):String; function isCNLeap(cnDate:TCNDate):boolean; implementation const cstDateOrg:Integer=32900; /公历 1990-01-27 的 TDateTime 表示 对
7、应农历 1990-01-01 const cstCNYearOrg=1990; const cstCNTable:arraycstCNYearOrgcstCNYearOrg + 60 of WORD=( / unsigned 16-bit 24402, 3730, 3366, 13614, 2647, 35542, 858, 1749, /1997 23401, 1865, 1683, 19099, 1323, 2651, 10926, 1386, /2005 32213, 2980, 2889, 23891, 2709, 1325, 17757, 2741, /2013 39850, 149
8、0, 3493, 61098, 3402, 3221, 19102, 1366, /2021 2773, 10970, 1746, 26469, 1829, 1611, 22103, 3243, /2029 1370, 13678, 2902, 48978, 2898, 2853, 60715, 2635, /2037 1195, 21179, 1453, 2922, 11690, 3474, 32421, 3365, /2045 2645, 55901, 1206, 1461, 14038); /2050 /建表方法: / 0101 111101010010 高四位是闰月位置,后 12 位表
9、示大小月 ,大月 30天,小月 29 天, /闰月一般算小月,但是有三个特例 2017/06,2036/06,2047/05 /对于特例则高四位的闰月位置表示法中的最高为设置为 1 特殊处理用 wLeapNormal 变量 / /2017/06 28330-61098 2036/06 27947-60715 2047/05 23133-55901 /如果希望用汇编,这里有一条信息:农历不会滞后公历 2 个月. /将公历转换为农历 /返回:12 位年份+4 位月份+5 位日期 function DecodeGregToCNDate(dtGreg:TDateTime):TCNDate; var i
10、DayLeave:Integer; wYear,wMonth,wDay:WORD; i,j:integer; wBigSmallDist,wLeap,wCount,wLeapShift:WORD; label OK; begin result := 0; iDayLeave := Trunc(dtGreg) - cstDateOrg; DecodeDate(IncMonth(dtGreg,-1),wYear,wMonth,wDay); if (iDayLeave 22295 )then Exit; /Raise Exception.Create(目前只能算 1990-01-27 以后的); /
11、Raise Exception.Create(目前只能算 2051-02-11 以前的); for i:=Low(cstCNTable) to High(cstCNTable) do begin wBigSmallDist := cstCNTablei; wLeap := wBigSmallDist shr 12; if wLeap 12 then begin wLeap := wLeap and 7; wLeapShift := 1; end else wLeapShift := 0; for j:=1 to 12 do begin wCount:=(wBigSmallDist and 1)
12、 + 29; if j=wLeap then wCount := wCount - wLeapShift; if iDayLeave 0; end; function GetGregDateFromCN(cnYear,cnMonth,cnDay:word;bLeap:Boolean=False):TDateTime; var i,j:integer; DayCount:integer; wBigSmallDist,wLeap,wLeapShift:WORD; begin / 0101 010010101111 高四位是闰月位置,后 12 位表示大小月 ,大月 30天,小月 29 天, DayC
13、ount := 0; if (cnYear 2050) then begin Result := 0; Exit; end; for i:= cstCNYearOrg to cnYear-1 do begin wBigSmallDist := cstCNTablei; if (wBIgSmallDist and $F000) 12 then begin wLeap := wLeap and 7; wLeapShift := 1; /大月在闰月. end else wLeapShift := 0; for j:= 1 to cnMonth-1 do begin DayCount:=DayCoun
14、t + (wBigSmallDist and 1) + 29; if j=wLeap then DayCount := DayCount + 29; wBigSmallDist := wBigSmallDist shr 1; end; if bLeap and (cnMonth = wLeap) then /是要闰月的吗? DayCount := DayCount + 30 - wLeapShift; result := cstDateOrg + DayCount + cnDay - 1; end; /将日期显示成农历字符串. function GregDateToCNStr(dtGreg:T
15、DateTime):String; const hzNumber:array010 of string=(零, 一,二,三,四,五,六,七,八,九, 十); function ConvertYMD(Number:Word;YMD:Word):string; var wTmp:word; begin result := ; if YMD = 1 then begin /年份 while Number 0 do begin result := hzNumberNumber Mod 10 + result; Number := Number DIV 10; end; Exit; end; if Nu
16、mber 0 then result := hzNumberwTmp; wTmp := Number Div 10; /十位 result:=十+result; if wTmp 1 then result := hzNumberwTmp + result; end; var cnYear,cnMonth,cnDay:word; cnDate:TCNDate; strLeap:string; begin cnDate:= DecodeGregToCNDate(dtGreg); if cnDate = 0 then begin result := 输入越界; Exit; end; cnDay := cnDate and $1F; cnMonth := (cnDate shr 5) and $F; cnYear := (cnDate shr 9) and $FFF; /测试第 22 位,为 1 表示闰月 if isCNLeap(cnDate) then strLeap:=(闰) else strLeap := ; result := 农历 + ConvertYMD(cnYear,1) + 年 + ConvertYMD(cnMonth,2) + 月 + strLeap + ConvertYMD(cnDay,3) ; end; end.