You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何计算指定日期的满月占比?求勘误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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:41:34