我的编程环境是Borland C ++ Builder 6。
我在以下代码中遇到了错误结果的问题:
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)));
结果为0而不是1!
为什么会这样?
答案 0 :(得分:0)
这是DateUtils
单元的旧版本中的一个已知问题,它最初是在Delphi / C ++ Builder 6中引入的。这个问题持续了几年,直到最终在Delphi / C ++中修复Builder XE。
TDateTime
基本上只是double
,其中日期存储在整数部分中,时间存储在小数部分中。因此,它需要进行近似表示和舍入。
在您的示例中,dtEnter
为42703.0340277778
,dtExit
为42703.0347222222
。
使用简单的浮点数学计算两个TDateTime
值之间的跨度:
function SpanOfNowAndThen(const ANow, AThen: TDateTime): TDateTime;
begin
if ANow < AThen then
Result := AThen - ANow
else
Result := ANow - AThen;
end;
在您的示例中,SpanOfNowAndThen(dtEnter, dtExit)
为0.000694444439432118
。
对于MinutesBetween()
函数,在XE之前,它会调用MinuteSpan()
,它会返回Double
,SpanOfNowAndThen()
的结果乘以{MinsPerDay
1}}常量,然后它将截断小数部分以产生最终整数:
function MinuteSpan(const ANow, AThen: TDateTime): Double;
begin
Result := MinsPerDay * SpanOfNowAndThen(ANow, AThen);
end;
function MinutesBetween(const ANow, AThen: TDateTime): Int64;
begin
Result := Trunc(MinuteSpan(ANow, AThen));
end;
在您的示例中,MinuteSpan()
生成的小数值略小于1.0
(确切地说为0.99999999278225
),当截断小数时,该值变为0。
在XE中,许多DateUtils
函数被重写以使用不基于浮点数学的更可靠的计算。虽然MinuteSpan()
仍然相同,但MinutesBetween()
不再使用MinuteSpan()
。相反,它现在将两个TDateTime
值转换为毫秒(由于TDateTime
具有毫秒精度,这是无损的),减去这些值,然后将差值的绝对值除以每个恒定的毫秒数分:
function DateTimeToMilliseconds(const ADateTime: TDateTime): Int64;
var
LTimeStamp: TTimeStamp;
begin
LTimeStamp := DateTimeToTimeStamp(ADateTime);
Result := LTimeStamp.Date;
Result := (Result * MSecsPerDay) + LTimeStamp.Time;
end;
function MinutesBetween(const ANow, AThen: TDateTime): Int64;
begin
Result := Abs(DateTimeToMilliseconds(ANow) - DateTimeToMilliseconds(AThen))
div (MSecsPerSec * SecsPerMin);
end;
在您的示例中,DateTimeToMilliseconds(dtEnter)
为63616063740000
,DateTimeToMilliseconds(dtExit)
为63616063800000
,因此差异为60000
毫秒,正是1
分钟。
对于XE之前的版本,您必须在自己的代码中手动实现类似的修复。这将在各种在线博客中讨论,例如:
How do I work around Delphi's inability to accurately handle datetime manipulations?