Es gab dazu vor einiger Zeit einige Bugfixes - die sind im fpc-Trunk (und kommen evt in fpc 3.04), weshalb Mathias als notorischer trunc-User das richtige Ergebnis erhält.
Das Problem ist das alte Problem mit den Gleitkommazahlen. TDateTime ist intern nichts anderes als Double und hat daher wie jedes andere Gleitkommaformat nur eine bestimmte Anzahl von Nachkommastellen. Da die Einheiten von TDateTime ganze Tage sind, sind Minuten unendlich lange Dezimalzahlen (Divisor 3) und können nicht exakt durch eine Double-Zahl ausgedrückt werden. Durch die Subtraktion kommt nochmals ein Rundungsfehler dazu.
Schau dir das folgende Programm an. Als Differenz, in Minuten ausgedrückt, erhält man 59.999999996507540. Trunc() macht daraus 59. Zwei Stunden früher machen die Rundungsfehler daraus etwas wie 60.000000006984919, wo das Trunc() den richtigen Wert ergibt.
Die Lösung ist immer, die halbe Einheit, auf die man runden möchte, also 0.5, dazuzuaddieren, und erst dann trunc zu nehmen. Damit wird aus 59.999999996507540 der Wert 60.499999..., was nach Trunc() zu den korrekten 60 wird; und der Wert von zwei Stunden früher, 60.000000006984919, wird zu 60.500000..., was nach Trunc() immer noch 60 bleibt. Also:
Code: Alles auswählen
program MinutesBetween_Test;
uses
SysUtils,
DateUtils;
procedure Test(d1, d2: TDateTime);
begin
WriteLn('d1: ', FormatDateTime('ddddd hh:nn:ss', d1), ' = ', d1);
WriteLn('d2: ', FormatDateTime('ddddd hh:nn:ss', d2), ' = ', d2);
WriteLn('MinutesBetween(d1, d2): ', MinutesBetween(d1, d2));
WriteLn('Differenz der Double-Werte als Minuten: ', (d2 - d1)*60*24);
WriteLn('Differenz nach Korrektur: ', (d2 - d1)*60*24 + 0.5);
WriteLn('Differenz nach Korrektur (gerundet): ', trunc((d2 - d1)*60*24 + 0.5));
WriteLn;
end;
begin
Test(EncodeDateTime(2017, 1, 1, 0, 0, 0, 0), EncodeDateTime(2017, 1, 1, 1, 0, 0, 0));
Test(EncodeDateTime(2016, 12, 31, 22, 0, 0, 0), EncodeDateTime(2016, 12, 31, 23, 0, 0, 0));
ReadLn;
end.