Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2010-05

<time_fraction>Between bug?

10 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bee Jay

Hi all,

Try the following code snippet:

uses
  DateUtils;
var
  a,b: TDateTime;
  i: integer;
begin
  a := EncodeDateTime(2010, 1, 1, 0, 0, 0, 0);
  for i := 0 to 9 do
  begin
    b := EncodeDateTime(2010, 1, 1, 0, 0, i, 0);
    Writeln(SecondsBetween(a,b):3);
  end;
end;

I think the result isn't correct. It also affects other <time_fraction>Between functions e.g. SecondsBetween, MinutesBetween, etc.

But if I changed the milisecond part of a or b or both to anything but 0 then the result is correct. Is this a bug? Or did I miss something?

TIA.

-Bee-

Reply by email

Marco van de Voort
to Bee Jay

In our previous episode, Bee Jay said:

Show quoted text 24 lines
Hi all, Try the following code snippet: uses DateUtils; var a,b: TDateTime; i: integer; begin a := EncodeDateTime(2010, 1, 1, 0, 0, 0, 0); for i := 0 to 9 do begin b := EncodeDateTime(2010, 1, 1, 0, 0, i, 0); Writeln(SecondsBetween(a,b):3); end; end; I think the result isn't correct. It also affects other <time_fraction>Between functions e.g. SecondsBetween, MinutesBetween, etc. But if I changed the milisecond part of a or b or both to anything but 0 then the result is correct. Is this a bug? Or did I miss something?

IIRC this is normal and delphi compatible and due to TDatetime being a floating point type.

*between does a trunc, and
"time" is a floating point values, so values might be rounded here and there.

Sometimes the rounding means that e.g. date+1second is rounded to a bit more than date + 1second. Then later secondsbetween sees no whole second between and this results in this behaviour.

Reply by email

Bee Jay
to Marco van de Voort
Marco van de Voort wrote
IIRC this is normal and delphi compatible and due to TDatetime being a floating point type.

No, it's not Delphi compatible. Delphi's result is alot worst, at least on Delphi 7. And I didn't ask to make it truly compatible with Delphi. ;)

*between does a trunc, and "time" is a floating point values, so values might be rounded here and there.

What if an app need a precise and correct result, say a rocket launcher? :D Is there other alternative solution?

Sometimes the rounding means that e.g. date+1second is rounded to a bit more than date + 1second. Then later secondsbetween sees no whole second between and this results in this behaviour.

What about other languages result? C or PHP, for example.

-Bee-

Reply by email

Bee Jay
to Jonas Maebe
Jonas Maebe wrote
Then it shouldn't use floating point. Ever.

Well... then it shouldn't be using FPC? ;)

Ok, forget about the rocket launcher. The important note that I think need to be addressed is the bug only occurs if the milisecond part of a or b is 0. Other than 0, then those functions work correctly.

I believe most of us rarely write a program that need precision to milisecond, usually we simply put 0 on the milisecond part. The worst thing is, the other similar functions e.g. HoursBetween etc. which commonly used are also affected by the bug. So, the simple thing could lead to a serious problem.

Should I report this to mantis?

-Bee-

Reply by email

Jonas Maebe
to Bee Jay
Bee Jay wrote 5 lines
2010, at 19:28, Jonas Maebe wrote: > Then it shouldn't use floating point. Ever. Well... then it shouldn't be using FPC? ;)

They should not be using any FPC functionality relying on floating point. Any person who uses floating point should know that by definition it is inexact (ranging from "a little" to "enormously", depending on what you do).

Ok, forget about the rocket launcher. The important note that I think need to be addressed is the bug only occurs if the milisecond part of a or b is 0. Other than 0, then those functions work correctly.

At least in the cases that you tested. There are almost certainly more cases where problems occur.

I believe most of us rarely write a program that need precision to milisecond, usually we simply put 0 on the milisecond part. The worst thing is, the other similar functions e.g. HoursBetween etc. which commonly used are also affected by the bug. So, the simple thing could lead to a serious problem.

That last sentence is a fundamental principle of any algorithm that uses floating point.

Should I report this to mantis?

No. If you need exact date/time calculations, you cannot use TDateTime. In fact, several of the TDateTime helpers are literally defined as only offering approximations (e.g. http://www.freepascal.org/docs-html/rtl/dateutils/monthspan.html).

You have to implement a separate unit that is written from the start to offer the precision that you require if you need more than what TDateTime offers.

Jonas

Reply by email

Marco van de Voort
to Bee Jay: Well... then it shouldn't be using FPC? ;) Ok, forget about the rocket launcher. The…

In our previous episode, Bee Jay said:

> Then it shouldn't use floating point. Ever. Well... then it shouldn't be using FPC? ;)

This kind of problems are universal, and TDateTime is a library invention. If you have an integer date based library, you can use that instead.

Show quoted text 9 lines
Ok, forget about the rocket launcher. The important note that I think need to be addressed is the bug only occurs if the milisecond part of a or b is 0. Other than 0, then those functions work correctly. I believe most of us rarely write a program that need precision to milisecond, usually we simply put 0 on the milisecond part. The worst thing is, the other similar functions e.g. HoursBetween etc. which commonly used are also affected by the bug. So, the simple thing could lead to a serious problem.

It is a limitation of *between definition and the used format. The information is not there, so nothing can be done. Therefore a bugreport would not make sense.

These are simple "handy and cheap" helper functions for relative imprecise business logic, nothing more.

For special purpose usage, one could make a separate unit. (e.g. base on a record type with two int64's). But start reading the calendar FAQ first. This is not the only problem with dates :-)

Reply by email

Bee Jay
to Jonas Maebe: They should not be using any FPC functionality relying on floating point. Any person who…
Jonas Maebe wrote
They should not be using any FPC functionality relying on floating point. Any person who uses floating point should know that by definition it is inexact (ranging from "a little" to "enormously", depending on what you do).

I understand.

That last sentence is a fundamental principle of any algorithm that uses floating point.

I see.

If you need exact date/time calculations, you cannot use TDateTime. In fact, several of the TDateTime helpers are literally defined as only offering approximations (e.g. http://www.freepascal.org/docs-html/rtl/dateutils/monthspan.html).

I understand that to have exact and precise date/time calculation, I can't use TDateTime. I am not asking for complete rewrite of DateUtils. I was just showing a small common mistake that could lead to a serious error in date/time calculation for common programming need. The source of the problem is clear. Can't we just supply a simple workaround for that bug? Instead of discussion about the risk of using floating point calculation.

Say for example, when msec part of a or b (in the previous code snippet) is equal to zero, the library will "autocorrect" it to prevent the bug arises. Or, the less precise functions e.g. HoursBetween, DaysBetween, etc could simply ignore the msec part. Common usage won't care about the msec anyway. The msec part would be truly taken into account on MilisecondsBetween function where the msec value does matter.

Or, at least, if we don't want to fix it, then state the bug clearly in the docs with "won't fix" status or something. So the users would have been warned since the beginning (I assume they read the docs) and they can carefully use TDateTime especially when involving msec part.

You have to implement a separate unit that is written from the start to offer the precision that you require if you need more than what TDateTime offers.

I don't need to write a rocket launcher app, yet. :D But if I do, I surely take your advice. I just want to use DateUtils unit safely by ignoring msec values which could lead to a serious bug while I don't really care about its value.

-Bee-

Reply by email

Bee Jay
to Marco van de Voort: In our previous episode, Bee Jay said: IIRC this is normal and delphi compatible and due…
But if I changed the milisecond part of a or b or both to anything but 0 then the result is correct.

Correction... the bug arises NOT only if the msec part is 0. The bug arises if msec part of both variables are EQUAL. If they are different, at least 1 msec, then those functions produce correct result.

See how serious the effect cause by this little bug...

Show quoted text 13 lines
uses DateUtils; var a,b: TDateTime; i: integer; begin a := EncodeDateTime(2010, 1, 1, 0, 0, 0, 0); for i := 0 to 9 do begin b := EncodeDateTime(2010+i, 1, 1, 0, 0, 0, 0); Writeln(YearsBetween(a,b):3); end; end;

Please note that I'm using YearsBetween in the above test. I'm not talking about superb precision in msec. The workaround is pretty trivial. If it compares the date part, both should at least have 1 day difference. If it compares the time part, both should at least have 1 msec difference. But I haven't done a thorough test, I might left other effects behind.

I think it'd be nice if it's corrected right from the DateUtils itself. Should I report it as bug?

-Bee-

Reply by email

Vinzent Höfler
to Bee Jay: No, it's not Delphi compatible. Delphi's result is alot worst, at least on Delphi 7. And…

Bee Jay :

[TDateTime]

What if an app need a precise and correct result, say a rocket launcher? :D Is there other alternative solution?

Yes. Use a time type based on a fixed point representation. This eliminates drift and accuracy issues cause by a floating point representation.

http://stop-me.svn.sourceforge.net/viewvc/stop-me/trunk/src/calendar.pas

may serve as an idea. ;)

(Still, the windows implementation, relying on MillisecondsBetween itself, still may not provide accurate clock times, so be careful.)

Vinzent.

GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT! Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01

Reply by email