Recent

Author Topic: DateTime functions  (Read 4431 times)

Hartmut

  • Hero Member
  • *****
  • Posts: 1028
Re: DateTime functions
« Reply #30 on: September 30, 2025, 04:10:34 pm »
I'm not aware of having seen an error with IncWeek() in the past. I will use your test program to try to find one
After I found such an error example with IncWeek() I detected, that some of the existing 'Expected dates' were not correct, so that their tests said "OK", although they were wrong. Meanwhile I saw, that you corrected them in https://gitlab.com/freepascal.org/fpc/source/-/issues/38424

So now we have 7 examples with IncWeek(), where errors occur:
Code: Pascal  [Select][+][-]
  1. // from procedure IncWeek_Test():
  2. Test(EncodeDateTime(1899,12,31, 0,0,0,0),      1, '1900-01-07 00:00:00');   // OK
  3. Test(EncodeDateTime(1899,12,31, 0,0,0,0),    -52, '1899-01-01 00:00:00');   // OK
  4. Test(EncodeDateTime(1899,12,31, 0,0,0,0), -10000, '1708-05-06 00:00:00');   // Error
  5. Test(EncodeDateTime(1899,12,31, 0,0,0,0),  -9999, '1708-05-13 00:00:00');   // Error
  6. Test(EncodeDateTime(1899,12,31, 0,0,0,0),  -9998, '1708-05-20 00:00:00');   // Error
  7.  
  8. Test(EncodeDateTime(1899,12,30, 0,0,0,0),      1, '1900-01-06 00:00:00');   // OK
  9. Test(EncodeDateTime(1899,12,30, 0,0,0,0),    -52, '1898-12-31 00:00:00');   // OK
  10. Test(EncodeDateTime(1899,12,30, 0,0,0,0), -10000, '1708-05-05 00:00:00');   // Error
  11. Test(EncodeDateTime(1899,12,30, 0,0,0,0),  -9999, '1708-05-12 00:00:00');   // Error
  12. Test(EncodeDateTime(1899,12,30, 0,0,0,0),  -9998, '1708-05-19 00:00:00');   // Error
  13.  
  14. Test(EncodeDateTime(1899,12,30, 0,0,0,0),  -1171, '1877-07-21 00:00:00');   // Error

And I found a typo in your new "incdatetime_tests.lpr":
Code: Pascal  [Select][+][-]
  1. const
  2. ...  // must be "USE_LOCAL_DATEUTILS":
  3. {$IF NOT DEFINED(USE_LCOAL_DATEUTILS) AND NOT DEFINED(USE_LOCAL_LINEAR_DATEUTILS)}
  4.   TDateTimeEpsilon = 2.2204460493e-16;  // Copied from FPC 3.3.1 where it is not public
  5. {$ENDIF}

You wrote in https://gitlab.com/freepascal.org/fpc/source/-/issues/38424
Quote
In the test project discussed below the minimum value is about 4E-15 so that all test cases are passed.
...
It turns out that no more errors are reported in the test cases when TDateTimeEpsilon is larger than 4E-15.

In my old notes I wrote, that I had found examples, where errors occured with 2.80E-14, which not occured with 2.85E-14
Maybe you want to add a note, that cases had been found, where even 2.80E-14 was too small.

And by random I saw this difference:
a) from reply #24 in this Topic =>
Code: Pascal  [Select][+][-]
  1. function TDateTime_to_LinearDate(aValue: TDateTime):double;
  2. begin
  3.   if (AValue >= 0) then
  4.     Result := AValue
  5.   else
  6.   if SameValue(Frac(AValue), 0.0, TDateTimeEpsilon) then
  7.     Result := Trunc(AValue)
  8.   else
  9.   if SameValue(Frac(AValue), -1.0, TDateTimeEpsilon) then
  10.     Result := Trunc(AValue) - 1
  11.   else
  12.     Result := Trunc(AValue) + Abs(Frac(AValue)); // with Abs()
  13. end;

b) from https://gitlab.com/freepascal.org/fpc/source/-/issues/39884 =>
Quote
Code: Pascal  [Select][+][-]
  1. function DateTimeToNumber(ADateTime: TDateTime): Double;
  2. begin
  3.   if (AValue >= 0) then
  4.     Result := AValue
  5.   else
  6.   if SameValue(Frac(AValue), 0.0, TDateTimeEpsilon) then
  7.     Result := Trunc(AValue)
  8.   else
  9.   if SameValue(Frac(AValue), -1.0, TDateTimeEpsilon) then
  10.     Result := Trunc(AValue) - 1
  11.   else
  12.     Result := Trunc(AValue) - Frac(AValue); // without Abs()
  13. end;
but I have no clue, which of them is wrong and should be corrected.

And a last proposal: const dateutils.TDateTimeEpsilon has caused repeatedly trouble in the past, but it was always intricate to make tests with other (better) values, because this const can't be changed easily for tests (this const is also used in the new functions DateTimeToNumber() and NumberToDateTime() introduced in https://gitlab.com/freepascal.org/fpc/source/-/issues/39884)
What about changing it to be a global typed const? Then it would be easy to try other values during tests. Or make it a local typed const and add a global procedure set_TDateTimeEpsilon() to change it temporarily. This would give much more flexibility.

RayoGlauco

  • Full Member
  • ***
  • Posts: 221
  • Beers: 1567
Re: DateTime functions
« Reply #31 on: September 30, 2025, 07:31:47 pm »
but I have no clue, which of them is wrong and should be corrected.

In this case, Abs(Frac(AVAlue)) = -Frac(AValue)  , because Frac(AValue) is allways a negative value.
To err is human, but to really mess things up, you need a computer.

RayoGlauco

  • Full Member
  • ***
  • Posts: 221
  • Beers: 1567
Re: DateTime functions
« Reply #32 on: October 01, 2025, 09:37:03 am »
I prefer to use Abs(Frac(AVAlue)), because it makes it clearer that the value to be added is positive. The logic behind negative TDateTimes is a bit of an unintuitive mess.
To err is human, but to really mess things up, you need a computer.

 

TinyPortal © 2005-2018