What the hell TDateTimeEpsilon actually is?
Since TDateTime is nothing but a floating point variable any calculation with them is affected by round-off error. This is particularly true for calculating date/time differences when the result has to be expressed as an integer which involves rounding.
Since the fractional part of a TDateTime variable is the time during this day, 0.000 refers to midnight, 0.25 to a quarter day, i.e. 6:00, 0.75 three quarters, i.e. 18:00 and so on. The numbers of minutes can be calculated as 24 hours * 60 minutes/hour = 1440. So, you can calculate the number of minutes between two dates or times as the difference of the DateTime values multiplied by 1440, the number of minutes per day. Since the result is a floating point value but you want only integer differences you must provide some rounding. Normally I would use the "Round()" function for this purpose. But this cannot be applied in date/time calculations where it is the convention to consider only full date/time periods. Suppose you have a child which was born on Jan 1, 2018. Calculating its age today (Sept 17, 2019) and using the "Round()" function would tell you that it is already 2 years old which is certainly not true - it is still 1 in common sense. Therefore, Trunc must be used instead of Round.
Using Trunc in floating point calculations, however, introduces the next problem that the result may be off by 1 in case of round-off error. Look at the following example:
program Project1;
uses
SysUtils, DateUtils;
function MyMinutesBetween(dt1, dt2: TDateTime): Integer;
begin
Result := Trunc((dt2 - dt1) * 24*60);
end;
var
dt1, dt2: TDateTime;
begin
dt1 := EncodeTime(3, 24, 51, 386);
dt2 := EncodeTime(3, 26, 51, 386);
WriteLn('Integer minutes between ',
FormatDateTime('hh:nn:ss.zzz', dt1), ' and ',
FormatDateTime('hh:nn:ss.zzz', dt2), ': ',
MyMinutesBetween(dt1, dt2)
);
WriteLn('Floating point minutes: ', (dt2 - dt1) * 24*60);
ReadLn;
end.
The test times dt1 and dt2 have an exact difference of two minutes (3:24:51.386 and 3:26:51.386), but the calculation based on a simple "hand-made" MinutesBetween() function reports that there is only 1!
How can this be? Round-off error: look at the un-rounded difference displayed in the next line: 1.9999999999999929 - a little bit less than 2 due to round-off errors, but the Trunc function makes it to a 1. A huge error!
How to prevent this? This is where TDateTimeEpsilon comes in. It is added to the unrounded difference to make it larger than the next integer value. So, the 1.9999999999999929 is converted to something like (just guessing) 2.000000000001. Applying trunc now results in the correct difference.
Of course, the value of TDateTimeEpsilon must be selected carefully. If it is too small it may not bring the difference value above the next integer. If it is too large it may result in another error when the "true" unrounded value is too close to the integer limit.
Since the smallest time interval handled by EncodeTime / DecodeTime is a millisecond you are probably on the safe side when the correction is selected as a small fraction of a millisecond, maybe 1 microsecond - there are 24*60*60 seconds per day, i.e. 86400 millions microseconds; so, the correction value could be 1/8.64E10 = 1.157E-11.
The MinutesBetween routine in DateUtils calculates the correction term as MinutesPerDay * TDateTimeEpsilon = 3.2E-13 which is even smaller by two orders of magnitude.