10

DateTime を OADate に変換しています。OADate を元に戻すときに正確に同じ DateTime を取得することを期待していましたが、現在はミリ秒の解像度しかないため、異なります。

var a = DateTime.UtcNow;
double oadate = a.ToOADate();
var b = DateTime.FromOADate(oadate);
int compare = DateTime.Compare(a, b); 

//Compare is not 0; the date times are not the same

からの目盛り: 634202170964319073

b からのティック: 634202170964310000

OADate ダブル: 40437.290467951389

これの理由は何ですか?DateTime の解像度は明らかに十分です。

4

3 に答える 3

15

これは素晴らしい質問だと思います。(私はちょうどそれを発見しました。)

1900 年にかなり近い日付で操作していない限り、aDateTimeはOA 日付よりも精度が高くなります。しかし、いくつかのあいまいな理由で、DateTime構造体の作成者は、 と他のものとの間で変換するときに、最も近い整数ミリ秒に切り捨てるのが大好きDateTimeです。言うまでもなく、これを行うと、正当な理由もなく多くの精度が失われます。

回避策は次のとおりです。

static readonly DateTime oaEpoch = new DateTime(1899, 12, 30);

public static DateTime FromOADatePrecise(double d)
{
  if (!(d >= 0))
    throw new ArgumentOutOfRangeException(); // NaN or negative d not supported

  return oaEpoch + TimeSpan.FromTicks(Convert.ToInt64(d * TimeSpan.TicksPerDay));
}

public static double ToOADatePrecise(this DateTime dt)
{
  if (dt < oaEpoch)
    throw new ArgumentOutOfRangeException();

  return Convert.ToDouble((dt - oaEpoch).Ticks) / TimeSpan.TicksPerDay;
}

さて、(あなたの質問から)DateTime与えられたものを考えてみましょう:

var ourDT = new DateTime(634202170964319073);
// .ToSting("O") gives 2010-09-16T06:58:16.4319073

any の精度DateTimeは 0.1 µs です。

私たちが検討している日付と時刻の近くで、OA 日付の精度は次のとおりです。

Math.Pow(2.0, -37.0)日、または約0.6286マイクロ秒

この地域では、aDateTimeは OA の日付よりも (わずかに) 6 倍正確であると結論付けています。

上記の拡張メソッドを使用して変換ourDTしましょうdouble

double ourOADate = ourDT.ToOADatePrecise();
// .ToString("G") gives 40437.2904679619
// .ToString("R") gives 40437.290467961888

ここで、上記の静的メソッドを使用して にourOADate戻すと、次のようになります。DateTimeFromOADatePrecise

2010-09-16T06:58:16.4319072(フォーマットで書かれてい"O"ます)

オリジナルと比較すると、この場合の精度の損失は 0.1 µs であることがわかります。この間隔の長さは 0.8 µs であり、前述の 0.6286 µs に匹敵するため、精度の低下は ±0.4 µs 以内であると予想されます。

double逆に、1900 年に近すぎない OA の日付を表すa から始めて、最初にを使用FromOADatePreciseし、次に を使用すると、中間の精度がOA の精度よりも優れているため、ToOADatePreciseに戻ります。この場合、完全な往復が期待されます。一方、BCL メソッドを同じ順序で使用すると、適切なラウンドトリップが得られる可能性は非常に低くなります (最初に使用したメソッドが非常に特殊な形式でない限り)。doubleDateTimeFromOADateToOADatedouble

于 2012-12-17T21:04:58.857 に答える
4

ToOADate によって呼び出される静的メソッドは、ティックを 10000 で明確に分割し、結果を long に格納するため、ミリ秒未満の情報を削除します。

OADate 形式の仕様を見つける場所を知っている人はいますか?

    private static double TicksToOADate(long value)
    {
        if (value == 0L)
        {
            return 0.0;
        }
        if (value < 0xc92a69c000L)
        {
            value += 0x85103c0cb83c000L;
        }
        if (value < 0x6efdddaec64000L)
        {
            throw new OverflowException(Environment.GetResourceString("Arg_OleAutDateInvalid"));
        }
        long num = (value - 0x85103c0cb83c000L) / 0x2710L;
        if (num < 0L)
        {
            long num2 = num % 0x5265c00L;
            if (num2 != 0L)
            {
                num -= (0x5265c00L + num2) * 2L;
            }
        }
        return (((double)num) / 86400000.0);
    }
于 2010-09-16T07:29:35.987 に答える
1

おそらく、DateTime ではなく、double の精度と関係があります。

于 2010-09-16T06:59:23.427 に答える