My Programming Environment is Borland C++ Builder 6.
I have encountered a problem with a bad result in the following code:
TDateTime dtEnter, dtExit;
dtEnter = EncodeDateTime(2016, 11, 29, 0, 49, 0, 0);
dtExit = EncodeDateTime(2016, 11, 29, 0, 50, 0, 0);
ShowMessage(dtEnter);
ShowMessage(dtExit);
ShowMessage(IntToStr(MinutesBetween(dtEnter, dtExit)));
The result is 0 instead of 1!
Why is this?
This is a known issue in older versions of the
DateUtils
unit, which was first introduced in Delphi/C++Builder 6. The issue lasted for several years until it was finally fixed in Delphi/C++Builder XE.TDateTime
is essentially just adouble
, where the date is stored in the integral portion and the time is stored in the fractional portion. As such, it is subject to approximate representations and rounding.In your example,
dtEnter
is42703.0340277778
anddtExit
is42703.0347222222
.The span between two
TDateTime
values is calculated using simple floating-point math:In your example,
SpanOfNowAndThen(dtEnter, dtExit)
is0.000694444439432118
.In the case of the
MinutesBetween()
function, prior to XE it would callMinuteSpan()
, which returns aDouble
that is the result ofSpanOfNowAndThen()
multiplied by theMinsPerDay
constant, and then it would truncate off the fractional portion to produce the final integer:In your example,
MinuteSpan()
produces a decimal value that is slightly less than1.0
(0.99999999278225
, to be exact), which becomes 0 when the decimal is truncated off.In XE, many of the
DateUtils
functions were re-written to use more reliable calculations that are not based on floating-point math. AlthoughMinuteSpan()
is still the same,MinutesBetween()
no longer usesMinuteSpan()
. Instead, it now converts the twoTDateTime
values to milliseconds (which is lossless sinceTDateTime
has millisecond precision), subtracts the values, and then divides the absolute value of the difference by a constant number of milliseconds per minute:In your example,
DateTimeToMilliseconds(dtEnter)
is63616063740000
andDateTimeToMilliseconds(dtExit)
is63616063800000
, so the difference is60000
ms, which is exactly1
minute.For versions prior to XE, you will have to implement a similar fix manually in your own code. This is discussed in various online blogs, such as:
How do I work around Delphi's inability to accurately handle datetime manipulations?
Accurate Difference Between Two TDateTime Values