Вот пример, демонстрирующий проблему:
var
fdt, fndt : Double;
dt, dt2 : TDateTime;
begin
dt := EncodeDateTime(2023, 12, 31, //
20, 10, 5, 100);
dt2 := EncodeTime(20, 10, 5, 100);
fdt := Frac(dt);
fndt := Frac(dt2);
Memo1.Lines.Add('Equal: ' + BoolToStr(fdt = fndt, True) + CRLF + //
FloatToStr(fdt) + CRLF + //
FloatToStr(fndt) + CRLF + //
FormatDateTime('HH:NN:SS ZZZ', fdt) + CRLF + //
FormatDateTime('HH:NN:SS ZZZ', fndt) + CRLF + //
''
);
Exit;
Результат:
Equal: False
0,840336805558763
0,840336805555556
20:10:05 100
20:10:05 100
Итак, как вы видите, часть времени — это не то же самое, что Double, а то же самое, что и форматированная строка.
Почему они разные?
Насколько я знаю, EncodeDateTime выполняет EncodeDate + EncodeTime. И Дата = Trunc(Дата). Значит дробная часть должна быть одинаковая! Но это не так. Почему? Может быть, есть информация о часовом поясе?
Спасибо за любую информацию об этом.
Конверт: Win 11, Delphi S10, 32-битный Exe. Часовой пояс: Европа/Будапешт (+2/+1).
Вы подсознательно полагаете, что, поскольку дата — целое число, а время — дробь, TDateTime содержит как целую, так и дробную часть?
Потому что так это работает. Если нам нужна только часть даты, мы должны использовать Trunc(DT), если нам нужно использовать часть времени, мы должны использовать Frac(DT). Из справки: «Целочисленная часть значения TDateTime — это количество дней, прошедших с 30 декабря 1899 года. Дробная часть значения TDateTime — это время суток». Я понимаю, что числа с плавающей запятой не содержат правильные значения. Но двойники в большинстве случаев правы в этих диапазонах. Так что это немного странно.
Итак, похоже, теперь я могу сравнить две части времени, если перекодирую их (Декодировать + Закодировать), и сравню эти перекодированные значения.
Не сравнивайте дату и время с =. Сделайте это с помощью TMath.SameValue(). Они двойники...





Сравнение значений с плавающей запятой на предмет равенства с помощью оператора = обычно не является точным из-за неточной природы типов с плавающей запятой. Тот факт, что входные данные идентичны, не гарантирует идентичности чисел с плавающей запятой.
Вы должны принять во внимание эпсилон, чтобы увидеть, являются ли значения с плавающей запятой «достаточно близкими», чтобы считаться равными. Для этой цели вы можете использовать Math.SameValue().
Однако в этом случае вы можете использовать DateUtils.SameTime() или DateUtils.CompareTime(). В документации SameTime() даже говорится следующее:
Примечание. Можно создать два значения TDateTime, временные части которых различаются численно, если рассматривать их как типы с плавающей запятой, но которые представляют одни и те же часы, минуты, секунды и миллисекунды. SameTime позволяет приложениям определять, когда два значения TDateTime представляют одно и то же время, даже если дробные части значений различаются.
В Delphi, как вы знаете, значения даты и времени являются числами с плавающей запятой (двойными числами), и именно так работают двойные значения. В WWW есть десятки тысяч вопросов по этой теме. Вот один из них: stackoverflow.com/questions/588004/…