2016-12-12 2 views
0

내 프로그래밍 환경은 내가 다음 코드에서 나쁜 결과에 문제가 발생했을 6.1 분 오류

볼랜드 C++ 빌더입니다 :

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

내가 C++ 빌더 10.1 베를린에서이 문제를 재현 할 수없는이는 등, 다양한 온라인 블로그에서 설명합니다. C++ Builder 6는 꽤 오래된 것입니다. 버그 일 수 있지만, 그러한 오래된 버그가 수정 될 확률은 0입니다. –

답변

0

이것은 Delphi/C++ Builder 6에서 처음 소개 된 DateUtils 유닛의 이전 버전에서 알려진 문제입니다.이 문제는 Delphi/C++ Builder XE에서 최종 수정 될 때까지 몇 년 동안 지속되었습니다.

TDateTime은 본질적으로 단지 double이며 날짜는 정수 부분에 저장되고 시간은 분수 부분에 저장됩니다. 따라서, 그것은 대략적인 진술과 반올림이 필요할 수 있습니다.

예에서 dtEnter42703.0340277778이고 dtExit42703.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

관련 문제