unit CNYear; interface uses sysutils; type TCNDate = Cardinal; function DecodeGregToCNDate(dtGreg:TDateTime):TCNDate; function GetGregDateFromCN(cnYearcnMonthcnDay:word;bLeap:Boolean=False): TDateTime; function GregDateToCNStr(dtGreg:TDateTime):String; function isCNLeap(cnDate:TCNDate):boolean; implementation const cstDateOrg:Integer=; //公历的TDateTime表示 对应农历 const cstCNYearOrg=; const cstCNTable:array[cstCNYearOrgcstCNYearOrg + ] of WORD=( // unsigned bit // // // // // // // ); // //建表方法 // 高四位是闰月位置后位表示大小月大月天小月 天 //闰月一般算小月但是有三个特例/// //对于特例则高四位的闰月位置表示法中的最高为设置为 特殊处理用wLeapNormal变 量 // /// > / > / > //如果希望用汇编这里有一条信息:农历不会滞后公历个月 //将公历转换为农历 //返回:位年份+位月份+位日期 function DecodeGregToCNDate(dtGreg:TDateTime):TCNDate; var iDayLeave:Integer; wYearwMonthwDay:WORD; ij:integer; wBigSmallDistwLeapwCountwLeapShift:WORD; label OK; begin result := ; iDayLeave := Trunc(dtGreg) cstDateOrg; DecodeDate(IncMonth(dtGreg)wYearwMonthwDay); if (iDayLeave < ) or (iDayLeave > )then Exit; //Raise ExceptionCreate(目前只能算以后的); //Raise ExceptionCreate(目前只能算以前的); for i:=Low(cstCNTable) to High(cstCNTable) do begin wBigSmallDist := cstCNTable[i]; wLeap := wBigSmallDist shr ; if wLeap > then begin wLeap := wLeap and ; wLeapShift := ; end else wLeapShift := ; for j:= to do begin wCount:=(wBigSmallDist and ) + ; if j=wLeap then wCount := wCount wLeapShift; if iDayLeave < wCount then begin Result := (i shl ) + (j shl ) + iDayLeave + ; Exit; end; iDayLeave := iDayLeave wCount; if j=wLeap then begin wCount:= + wLeapShift; if iDayLeave < wCount then begin Result := (i shl ) + (j shl ) + iDayLeave + + ( shl ); Exit; end; iDayLeave := iDayLeave wCount; end; wBigSmallDist := wBigSmallDist shr ; end; end; //返回值: // 位闰月标志 + 位年份+位月份+位日期 (共位) end; function isCNLeap(cnDate:TCNDate):boolean; begin result := (cnDate and $) <> ; end; function GetGregDateFromCN(cnYearcnMonthcnDay:word;bLeap:Boolean=False): TDateTime; var ij:integer; DayCount:integer; wBigSmallDistwLeapwLeapShift:WORD; begin // 高四位是闰月位置后位表示大小月大月天小月 天 DayCount := ; if (cnYear < ) or (cnYear >) then begin Result := ; Exit; end; for i:= cstCNYearOrg to cnYear do begin wBigSmallDist := cstCNTable[i]; if (wBIgSmallDist and $F) <> then DayCount := DayCount + ; DayCount := DayCount + * ; for j:= to do begin DayCount := DayCount + wBigSmallDist and ; wBigSmallDist := wBigSmallDist shr ; end; end; wBigSmallDist := cstCNTable[cnYear]; wLeap := wBigSmallDist shr ; if wLeap > then begin wLeap := wLeap and ; wLeapShift := ; //大月在闰月 end else wLeapShift := ; for j:= to cnMonth do begin DayCount:=DayCount + (wBigSmallDist and ) + ; if j=wLeap then DayCount := DayCount + ; wBigSmallDist := wBigSmallDist shr ; end; if bLeap and (cnMonth = wLeap) then //是要闰月的吗? DayCount := DayCount + wLeapShift; result := cstDateOrg + DayCount + cnDay ; end; //将日期显示成农历字符串 function GregDateToCNStr(dtGreg:TDateTime):String; const hzNumber:array[] of string=(零一二三四五六 七八九十); function ConvertYMD(Number:Word;YMD:Word):string; var wTmp:word; begin result := ; if YMD = then begin //年份 while Number > do begin result := hzNumber[Number Mod ] + result; Number := Number DIV ; end; Exit; end; if Number<= then begin //可只用位 if YMD = then //月份 result := hzNumber[Number] else //天 result := 初 + hzNumber[Number]; Exit; end; wTmp := Number Mod ; //个位 if wTmp <> then result := hzNumber[wTmp]; wTmp := Number Div ; //十位 result:=十+result; if wTmp > then result := hzNumber[wTmp] + result; end; var cnYearcnMonthcnDay:word; cnDate:TCNDate; strLeap:string; begin cnDate:= DecodeGregToCNDate(dtGreg); if cnDate = then begin result := 输入越界; Exit; end; cnDay := cnDate and $F; cnMonth := (cnDate shr ) and $F; cnYear := (cnDate shr ) and $FFF; //测试第位为表示闰月 if isCNLeap(cnDate) then strLeap:=(闰) else strLeap := ; result := 农历 + ConvertYMD(cnYear) + 年 + ConvertYMD(cnMonth) + 月 + strLeap + ConvertYMD(cnDay) ; end; end |