[Lazarus] Bump issue

R.Smith ryansmithhe at gmail.com
Sat Jan 23 00:46:58 CET 2021


On 2021/01/22 23:58, Marco van de Voort via lazarus wrote:
>
> Op 2021-01-22 om 22:56 schreef Michael Van Canneyt via lazarus:
>>
>>
>> I have some time this weekend, I will commit it.
>
> Is it really a good idea to accept msec=1000 for TryEncodeTimeInterval 
> in a general unit like Dateutils?
>
>
Maybe - can you construe a situation where the allowance would cause 
undue error or miscalculation of a datetime?  It's essentially an 
allowance for rounding. If your date-time calculation tries to add 
999.999ms or 0.9999 sec to a datetime value, would you really be harmed 
if one full second was added? If so, what does it say for the occasion 
where you add 0.1116s and either 0.112s or 0.111s are physically added 
after rounding/truncation - is the prior any worse? Currently rounding 
works in all cases (000.000 up to 999.99444) except the very final 0.5ms 
of the range, and code has to be added to everything to fix that small 
remainig range because rounding perfectly *valid* time values to ms = 
1000 will error out.

I can and have demonstrated a case where NOT allowing msec=1000 is in 
fact detrimental and breaks in current production code (as far as the 
MySQL connection DATETIME values go) for any datetime fraction nearing 
lim{ dt --> 1000ms }. Allow me another demonstration without the DB stuff:

Reproducible test case:
Getting the current ms can be easily written as:
ms := Round(Frac(Now() * 86400)*1000);    // ms is the fraction of the 
seconds multiplied by 1000 and rounded.

Here is a full test-case anyone can run:

procedure timetest;
   var ms   : Integer;
       dtms : TDateTime;
begin
   try
     repeat
       ms := Round(Frac(Now() * 86400)*1000);
       dtms := EncodeTime(00,00,00,ms);
     until false;
   finally
     WriteLn('ms: ',ms);
   end;
end;

It errors out rather quick with the 1000ms culprit problem.

Now as a programmer i have to either TRUNCATE the time, which is not 
great because 12.9ms will become 12ms in stead of 13ms, or add special 
code to test for ms=1000, and what is worse, that code is almost always:

       if (ms=1000) then dtms := EncodeTime(00,00,01,00) else dtms := 
EncodeTime(00,00,00,ms);

I hope it is not lost on any readers how silly that is - I mean what 
ELSE could one possibly end up doing/meaning in the case of 1000ms?.
I will even argue that can be detrimental since I have seen fixes like this:

       if (ms=1000) then ms:=999;
       dtms := EncodeTime(00,00,00,ms);

which drives me to tears of course, but one could almost understand why 
the programmer did that, sacrificing accuracy to get rif of a silly 
exception. It isn't FPC's fault though, that is just a bad programmer.

As programmers our duty is to make our code conform strictly to the 
rules of the underlying systems, and I have been quite a vocal advocate 
for this on other fora - but rules should have clear reasons, not simply 
be rules for the sake of having rules - which comes to my challenge of 
showing a case where it is detrimental.

There was a proposal to compute the specific datetime value for the 
MySQL connector itself in Floating point space, which is a perfect 
solution (and I will be very happy with that too), but does it address 
the full spectrum of plausible cases? Would this need to be fixed in the 
PostGres (etc.) connectors too? Fixing it at the root of date-time 
calculations when the change is indeed sensible, AND barring 
demonstrable "bad" cases (I hasten to add), seems the appropriate thing 
to do.

Lastly...

In other datetime calcs, if you try to add a day that doesn't exist (ex: 
dt := EncodeDate(2021,02,30); ) then the reason it is wrong is clear and 
it should error out, that date does not exist in current calendars. 
Adding 25ms to 02:15:04.975ms simply lands you at 02:15:05.000 - It's 
hard to for me to find a reasonable example of where that will cause 
undue error or a result that is fundamentally wrong.

The only thing I can think that might be a problem is a programmer 
seeing that EncodeTime(02,15,40,1000) yields --> 02:15:41.  It's not 
technically wrong, but would this be unexpected? Would it confuse 
people? (Moreso than throwing an exception?)
If this is the solution we go with, this 1000ms case should probably be 
mentioned clearly in the documentation.


PS: I work with precision time a lot, GPS tracking systems etc, so for 
my use cases this is probably way more of a niggle than everyone else, 
so I concede my opinion doesn't carry all that much weight, but I really 
do not see the harm in fixing this for everyone - unless it can be shown 
to be detrimental, in which case I will happily accept it and appreciate 
being shown it.


Thank you for caring!
Ryan



More information about the lazarus mailing list