이것은 Delphi/C++ Builder 6에서 처음 소개 된 DateUtils
유닛의 이전 버전에서 알려진 문제입니다.이 문제는 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()
함수의 경우
은 종래 그것이
MinsPerDay
상수를 곱한
SpanOfNowAndThen()
의 결과 인
Double
를 반환하는
MinuteSpan()
부를 것이다 XE하고, 그것은 최종 정수를 제조하는 소수 부분을 절단 할 : 당신의 예에서
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()
는 소수점이 꺼립니다 때 0이 약간 미만 1.0
진수 값 (0.99999999278225
, 정확하게하기)를 생산하고 있습니다.
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
ms이며 정확히 1
분입니다.
XE 이전 버전의 경우 사용자 자신의 코드에서 수동으로 유사한 수정 프로그램을 구현해야합니다.
How do I work around Delphi's inability to accurately handle datetime manipulations?
Accurate Difference Between Two TDateTime Values
내가 C++ 빌더 10.1 베를린에서이 문제를 재현 할 수없는이는 등, 다양한 온라인 블로그에서 설명합니다. C++ Builder 6는 꽤 오래된 것입니다. 버그 일 수 있지만, 그러한 오래된 버그가 수정 될 확률은 0입니다. –