如何计算指定日期的满月占比?求勘误Delphi代码
Delphi满月占比计算代码问题排查
我需要计算指定日期的满月占比,但自行编写的Delphi代码计算结果有误,当前实际满月占比约为96.9%,请帮忙排查代码问题。以下是我的Delphi代码:
procedure TfrmLag.btnCalcClick(Sender: TObject); var whatDate : TDateTime; // Now; lunarDays : Double; // 29.53058770576 lunarSecs : LongInt; // lunarDays * (24*60*60); new2000 : TDateTime; // 6.1 2000 18:14 totalSecs : LongInt; // whatDate - new2000 currSecs : LongInt; // totalSecs MOD lunarSecs currFrac : Double; // currSecs / lunarSecs currDays : LongInt; // currFrac * lunarDays perOfFull : Double; begin whatDate := Now; lunarDays := 29.53058770576; lunarSecs := Round(lunarDays * (24*60*60)); new2000 := EncodeDateTime(2000,1,6,18,14,00,000); totalSecs := SecondsBetween(whatDate, new2000); currSecs := totalSecs MOD lunarSecs; currFrac := currSecs / lunarSecs; currDays := Round(currFrac*lunarDays); perOfFull := (100*currFrac); lb.Items.Add('Date : '+FormatDateTime('dd.mm.yyyy hh:mm:ss',whatDate)); lb.Items.Add('Lunar days : '+IntToStr(lunarSecs)); lb.Items.Add('First full 2000 : '+FormatDateTime('dd.mm.yyyy hh:mm:ss',new2000)); lb.Items.Add('Total seconds : '+IntToStr(totalSecs)); lb.Items.Add('Current seconds : '+IntToStr(currSecs)); lb.Items.Add('Current fraction : '+FloatToStr(currFrac)); lb.Items.Add('Current days : '+IntToStr(currDays)); lb.items.Add('Percent of full : '+FloatToStr(perOfFull)); end;
问题排查与修正
1. 基准时间错误
代码中new2000标注为“First full 2000”,但2000年1月6日18:14实际是新月(朔),而非满月(望)。满月出现在新月后约14.765天,基准点错误会导致整个月相计算偏移。
2. 满月占比逻辑完全错误
当前代码直接将currFrac*100作为满月占比,这是错误的:
- 月相周期中,0(新月)→0.5(满月)是月亮逐渐变满的过程,占比从0%到100%
- 0.5(满月)→1(下一个新月)是月亮逐渐变缺的过程,占比从100%回到0%
正确的占比计算应该基于当前相位距离满月的位置,而非直接取周期占比。
3. 精度损失问题
- 用
Round将朔望月周期转换为整数秒,会引入误差,应保留浮点数计算 SecondsBetween获取整数秒差,损失了毫秒级精度,直接用TDateTime的差值计算更准确
修正后的代码
procedure TfrmLag.btnCalcClick(Sender: TObject); var whatDate : TDateTime; lunarDays : Double; // 朔望月周期,29.53058770576天 fullMoon2000 : TDateTime; // 2000年第一个满月:2000-01-21 07:37 daysBetween : Double; // 目标日期与基准满月的天数差 currFrac : Double; // 月相周期内的位置(0~1) perOfFull : Double; // 满月占比(0%~100%) begin whatDate := Now; lunarDays := 29.53058770576; // 修正基准时间为2000年第一个满月 fullMoon2000 := EncodeDateTime(2000, 1, 21, 7, 37, 0, 0); // 高精度计算天数差(TDateTime本身是双精度浮点数,代表从1899-12-30起的天数) daysBetween := whatDate - fullMoon2000; // 取周期内的小数部分,得到当前在月相周期中的位置 currFrac := Frac(daysBetween / lunarDays); // 计算满月占比:新月→满月→新月的变化曲线 if currFrac <= 0.5 then perOfFull := currFrac * 200 // 0→0.5对应0%→100% else perOfFull := (1 - currFrac) * 200; // 0.5→1对应100%→0% // 输出格式化信息 lb.Items.Add('日期 : '+FormatDateTime('dd.mm.yyyy hh:mm:ss', whatDate)); lb.Items.Add('朔望月周期(天) : '+FloatToStr(lunarDays)); lb.Items.Add('2000年第一个满月 : '+FormatDateTime('dd.mm.yyyy hh:mm:ss', fullMoon2000)); lb.Items.Add('天数差 : '+FloatToStr(daysBetween)); lb.Items.Add('周期内位置 : '+FloatToStr(currFrac)); lb.Items.Add('满月占比 : '+FormatFloat('0.0%', perOfFull / 100)); end;
内容的提问来源于stack exchange,提问作者Sjubussen
相关产品推荐
相关产品推荐

