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
DateUtilsunit, 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.TDateTimeis 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,
dtEnteris42703.0340277778anddtExitis42703.0347222222.The span between two
TDateTimevalues 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 aDoublethat is the result ofSpanOfNowAndThen()multiplied by theMinsPerDayconstant, 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
DateUtilsfunctions 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 twoTDateTimevalues to milliseconds (which is lossless sinceTDateTimehas 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)is63616063740000andDateTimeToMilliseconds(dtExit)is63616063800000, so the difference is60000ms, which is exactly1minute.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