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;
source to share
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.
source to share
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;
source to share