2016-12-12 9 views
0

私のプログラミング環境は、私は次のコードで悪い結果に問題が発生した61分エラー

ボーランドC++ Builderのです:

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++ Builder 6はかなり古くなっています。バグかもしれませんが、そのような古いバグが修正される可能性はゼロです。 –

答えて

0

これは、Delphi/C++ Builder 6で初めて導入されたDateUtilsユニットの旧バージョンでの既知の問題です。この問題は、Delphi/C++ Builder XEで最終的に修正されるまで数年間続きました。

TDateTimeは本質的にはdoubleであり、日付は整数部分に格納され、時間は小数部分に格納されます。したがって、それはおおよその表現と丸めの対象となります。

この例では、dtEnter42703.0340277778であり、dtExit42703.0347222222です。 SpanOfNowAndThen(dtEnter, dtExit)0.000694444439432118である、あなたの例で

function SpanOfNowAndThen(const ANow, AThen: TDateTime): TDateTime; 
begin 
    if ANow < AThen then 
    Result := AThen - ANow 
    else 
    Result := ANow - AThen; 
end; 

2つのTDateTime値の間のスパンは、単純な浮動小数点演算を用いて計算されます。 MinsPerDay定数を乗じSpanOfNowAndThen()の結果であるDoubleを返すことがMinuteSpan()を呼び出すことになるXE前MinutesBetween()関数の場合

、そしてそれは、最終的な整数を生成するように小数部分を切り捨てオフになります:あなたの例で

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となる(正確には、0.999999992782251.0よりもわずかに小さい小数値を生成します。

XEでは、浮動小数点数学に基づいていないより信頼性の高い計算を使用するために、多くの関数DateUtilsが書き直されました。 MinuteSpan()はまだ同じですが、MinutesBetween()はもうMinuteSpan()を使用しません。その代わりに、それは今、(TDateTimeは、ミリ秒の精度を有するため、可逆である)ミリ秒に2つの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ミリ秒であり、正確には1分です。

XEより前のバージョンでは、独自のコードで手動で同様の修正プログラムを実装する必要があります。私はC++ Builderの10.1ベルリンでこれを再現することはできません

How do I work around Delphi's inability to accurately handle datetime manipulations?

Accurate Difference Between Two TDateTime Values