Why does this code only work twice?

I have this code that only works twice with variables DateStart: = 27-01-2013 DateStop: = 31-03-2013

I think it should work with results 31-01-2013, 28-02-2013 and 31-3-2013 But I am only getting 2 results

I'm sure I've looked a lot and don't see the problem

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;

      

+3


source to share


2 answers


Either FsFutureCreate

(which you never told us what it is) has some side effects, or you have a floating point fuzz problem. As you know, date and time values ​​are doubled, so comparisons like <=

are dangerous. (Especially if you ignore the timing part, as my analysis below shows).

The second option is most likely. I just tried

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;

      

and received false

as you would expect. Hence the problem in this case is that the function EndOfTheMonth

also sets the time to the last second (or millisecond) of the day. Even if it isn't, making comparisons with = is dangerous when it comes to floating point values.

To correct your comparison, do



CompareDate(d, d2) <= 0

      

instead

d <= d2.

      

I leave this as an exercise to find out using the documentation why this works and is reliable.

+3


source


The reason is that it EndOfTheMonth

gives you the last day of the month, but also the time corresponding to the end of the day. But yours DateStop

is probably the very beginning of the day.

If you print the original values DateStart

and DateStop

in a loop, you see the following:

41333.9999999884 41364
41364.9999999884 41364

      



So looking at the final line, you can see that we have a time of 23:59 on day 41364.

I will fix this by working with clean dates and not letting the time get in the way of things. Change the incremental code to remove the time portion of the date. And I would also like to do the same in a loop test.

while DateOf(DateStart) <= DateOf(DateStop) do
begin
  ....
  DateStart := DateOf(EndOfTheMonth(IncMonth(DateStart)));
end;

      

+2


source







All Articles