3

変数 DateStart := 27-01-2013 DateStop := 31-03-2013 で 2 回だけ実行されるこのコードがあります。

2013 年 1 月 31 日、2013 年 2 月 28 日、2013 年 3 月 31 日の結果で実行する必要があると思いますが、結果は 2 つしか得られません

私はよく見つめていて、問題が見えないことは確かです

begin
  DateStart := EndOfTheMonth(DateStart);
  while DateStart <= DateStop do
    begin
      FsFutureCreate(DateStart, cxDebit.Value, cxKredit.Value, aAccount, aType, aStore, aCity, txtText.Text, lRecord);
      DateStart := EndOfTheMonth(IncMonth(DateStart));
    end;
end;
4

2 に答える 2

3

(それが何であるか FsFutureCreateを教えてくれなかった)副作用がある、浮動小数点ファズに問題があります。ご存じのとおり、日付と時刻の値は double であるため、 のような比較<=は危険です。(特に、以下の私の分析が示すように、時間の部分を無視した場合。)

2番目のものは、より可能性の高いものです。やってみました

procedure TForm1.FormCreate(Sender: TObject);
var d: TDate; d2: TDate;
begin
  d := EncodeDate(2013, 01, 31);
  d := IncMonth(d);                          // 2013-02-28
  d := EndOfTheMonth(d);                     // 2013-02-28
  d := IncMonth(d);                          // 2013-03-28
  d := EndOfTheMonth(d);                     // 2013-03-31

  d2 := EncodeDate(2013, 03, 31);

  // d is now 2013-03-31 23:59:59
  // d2 is now 2013-03-31 00:00:00

  ShowMessage(BoolToStr(d <= d2, true));

end;

falseそして、予想通り、を得ました。したがって、この場合の問題は、EndOfTheMonth関数が時刻を 1 日の最後の秒 (またはミリ秒) に設定することです。しかし、そうでなかったとしても、浮動小数点値に関しては = を使用して比較を行うのは危険です。

比較を修正するには、次のようにします。

CompareDate(d, d2) <= 0

それ以外の

d <= d2.

ドキュメントを使用して、これが機能し、堅牢である理由を見つけるための演習として残します。

于 2013-01-27T20:10:41.103 に答える
2

その理由はEndOfTheMonth、月の最終日だけでなく、1 日の終わりに対応する時刻も提供するためです。しかし、あなたDateStopはおそらく一日の始まりです。

DateStartループ内のとの生の値を出力するとDateStop、次のように表示されます。

41333.9999999884 41364
41364.9999999884 41364

最後の行を見ると、41364 日の 23:59 の時間が表示されていることがわかります。

純粋な日付で作業し、時間が邪魔にならないようにすることで、これを修正します。増分コードを変更して、日付の時刻部分を削除します。また、ループ テストで同じことを行うことについても明確にします。

while DateOf(DateStart) <= DateOf(DateStop) do
begin
  ....
  DateStart := DateOf(EndOfTheMonth(IncMonth(DateStart)));
end;
于 2013-01-27T20:10:51.053 に答える