给定
a := StrToTime('7:00');
b := StrToTime('17:30');
ShowMessage(FloatToStr(a));
ShowMessage(FloatToStr(b));
您的代码使用
MinutesBetween
实现了以下效果:
ShowMessage(IntToStr(trunc(MinuteSpan(a, b))))
然而,四舍五入可能更好:
ShowMessage(IntToStr(round(MinuteSpan(a, b)))); // Gives 630
实际上是什么浮点数值?
ShowMessage(FloatToStr(MinuteSpan(a, b))); // Gives 630
所以你显然正在遭受传统浮点问题的困扰。
更新:
Round
的主要优点是,如果分钟跨度非常接近整数,则四舍五入后的值保证是该整数,而截断后的值很可能是前面的整数。
Trunc
的主要优点在于你可能确实需要这种逻辑:实际上,如果你再过五天就满18岁了,法律上仍然不允许你申请瑞典驾照。
因此,如果你想使用 Round
而不是 Trunc
,只需添加
function MinutesBetween(const ANow, AThen: TDateTime): Int64;
begin
Result := Round(MinuteSpan(ANow, AThen));
end;
将此函数添加到您的单元中。然后,标识符MinutesBetween
将引用同一单元中的此函数,而不是DateUtils
中的函数。通常规则是编译器将使用最新找到的函数。因此,例如,如果您将此函数放在自己的单元DateUtilsFix
中,则
implementation
uses DateUtils, DateUtilsFix
将使用新的MinutesBetween
,因为DateUtilsFix
出现在DateUtils
右侧。
更新2:
另一个可行的方法可能是
function MinutesBetween(const ANow, AThen: TDateTime): Int64;
var
spn: double;
begin
spn := MinuteSpan(ANow, AThen);
if SameValue(spn, round(spn)) then
result := round(spn)
else
result := trunc(spn);
end;
这将返回
round(spn)
,如果
在模糊范围内为整数,则为spn,否则返回
trunc(spn)
。
例如,使用此方法:
07:00:00 and 07:00:58
将会得到0分钟,就像使用原始的基于
trunc
的版本一样,也就是瑞典Trafikverket所希望的。但它不会遇到引发问题的OP的问题。
TDateTime
存在一个大问题,它们是表示天数的双精度浮点数,而不是固定点数。这意味着它们无法准确地表示分钟。(不确定是否正是这个原因导致了问题,但我并不感到惊讶) - CodesInChaosTDateTime
比较例程的大多数问题,请参阅 John Herbsters 的 QC 报告 56957,他提出了一些改进建议。这个建议也被 Zarko Gajic 描述在:accurate-difference-between-two-delphi-tdatetime-values。正如评论中所指出的,这些缺陷在后来的 Delphi 版本中得到了纠正。 - LU RD