Search code examples
datetimedelphitimedifferencefractions

Delphi EncodeDateTime and EncodeTime Time portions are different


Here is an example which demonstrates the problem:

var
   fdt, fndt : Double;
   dt, dt2 : TDateTime;
begin
    dt := EncodeDateTime(2023, 12, 31, //
        20, 10, 5, 100);
    dt2 := EncodeTime(20, 10, 5, 100);
    fdt := Frac(dt);
    fndt := Frac(dt2);
    Memo1.Lines.Add('Equal: ' + BoolToStr(fdt = fndt, True) + CRLF + //
        FloatToStr(fdt) + CRLF +  //
        FloatToStr(fndt) + CRLF +  //
        FormatDateTime('HH:NN:SS ZZZ', fdt) + CRLF +  //
        FormatDateTime('HH:NN:SS ZZZ', fndt) + CRLF +  //
        ''
        );
    Exit;

The result is:

 Equal: False 
 0,840336805558763 
 0,840336805555556 
 20:10:05 100
 20:10:05 100

So as you see the Time portion is not the same as Double, but same as Formatted String.

Why they are different?

As I know that EncodeDateTime does EncodeDate + EncodeTime. And the Date = Trunc(Date). So the fractional part has to be same! But it isn't. Why? Maybe some time zone info?

Thank you for any info about it.

Env: Win 11, Delphi S10, 32bit Exe. Time zone: Europe/Budapest (+2/+1).


Solution

  • Comparing floating point values for equality using the = operator is generally not accurate due to the inaccurate nature of floating point types. Just because the inputs are identical does not guarantee the floats are identical.

    You have to take an epsilon into account to see if floating point values are "close enough" to be considered equal. You can use Math.SameValue() for that purpose.

    However, in this case, you can use DateUtils.SameTime() or DateUtils.CompareTime() instead. The SameTime() documentation even states the following:

    Note: It is possible to create two TDateTime values whose time portions differ numerically when viewed as floating point types, but which represent the same hour, minute, second, and millisecond. SameTime allows applications to determine when two TDateTime values represent the same time, even when the fractional parts of the values differ.