[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