web-dev-qa-db-ja.com

C#DateTime.Now精度

いくつかの単体テストを行っているときに、DateTime.UtcNowで予期しない動作が発生しました。 DateTime.Now/UtcNowを連続して呼び出すと、より正確なミリ秒単位の増分をキャプチャするのではなく、予想よりも長い時間間隔で同じ値を返すように見えます。

正確な時間測定を行うのに適したストップウォッチクラスがあることは知っていますが、誰かがこの動作をDateTimeで説明できるかどうか興味がありましたか? DateTime.Nowについて文書化された公式の精度はありますか(たとえば、50ミリ秒以内の精度ですか?)。 DateTime.Nowの精度が、ほとんどのCPUクロックで処理できるものよりも低くなるのはなぜですか?たぶん、最小の共通分母CPU向けに設計されただけでしょうか?

public static void Main(string[] args)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int i=0; i<1000; i++)
    {
        var now = DateTime.Now;
        Console.WriteLine(string.Format(
            "Ticks: {0}\tMilliseconds: {1}", now.Ticks, now.Millisecond));
    }

    stopwatch.Stop();
    Console.WriteLine("Stopwatch.ElapsedMilliseconds: {0}",
        stopwatch.ElapsedMilliseconds);

    Console.ReadLine();
}
90
Andy White

DateTime.Nowの精度が、ほとんどのCPUクロックで処理できるものよりも低くなるのはなぜですか?

良いクロックは正確正確の両方でなければなりません。それらは異なります。古いジョークのように、停止した時計は1日に2回正確に正確であり、1分の遅い時計はいつでも正確ではありません。しかし、1分間遅いクロックは常に最も近い分まで正確です。一方、停止したクロックは有用な精度をまったく持ちません。

DateTimeを正確なに、なぜマイクロ秒に正確なにできないのに、なぜマイクロ秒にすべきなのでしょうか?ほとんどの人は、マイクロ秒単位の正確な公式時間信号のソースを持ちません。したがって、精度の小数点以下6桁を与えると、最後の5つはガベージになり、lyingになります。

DateTimeの目的は、日付と時刻を表すであることを忘れないでください。高精度のタイミングは、DateTimeの目的ではありません。ご指摘のとおり、これがStopWatchの目的です。 DateTimeの目的は、ユーザーに現在の時刻を表示する、次の火曜日までの日数を計算するなどの目的で日付と時刻を表すことです。

要するに、「今は何時ですか?」そして「それはどれくらいかかりましたか?」完全に異なる質問です。 1つの質問に答えるために設計されたツールを使用しないでください。

質問をありがとう。これは良いブログ記事になります! :-)

171
Eric Lippert

DateTimeの精度は、実行されているシステムにある程度固有です。精度は、コンテキストスイッチの速度に関連しており、15または16ミリ秒程度になる傾向があります。 (私のシステムでは、実際にはテストから約14ミリ秒ですが、ラップトップで35〜40ミリ秒の精度に近いものを見てきました。)

Peter Brombergは、C#で 高精度コードタイミングに関する記事 を書きました。

18
Reed Copsey

正確なDatetime.Now :)が欲しいので、これを作りました:

public class PreciseDatetime
{
    // using DateTime.Now resulted in many many log events with the same timestamp.
    // use static variables in case there are many instances of this class in use in the same program
    // (that way they will all be in sync)
    private static readonly Stopwatch myStopwatch = new Stopwatch();
    private static System.DateTime myStopwatchStartTime;

    static PreciseDatetime()
    {
        Reset();

        try
        {
            // In case the system clock gets updated
            SystemEvents.TimeChanged += SystemEvents_TimeChanged;
        }
        catch (Exception)
        {                
        }
    }

    static void SystemEvents_TimeChanged(object sender, EventArgs e)
    {
        Reset();
    }

    // SystemEvents.TimeChanged can be slow to fire (3 secs), so allow forcing of reset
    static public void Reset()
    {
        myStopwatchStartTime = System.DateTime.Now;
        myStopwatch.Restart();
    }

    public System.DateTime Now { get { return myStopwatchStartTime.Add(myStopwatch.Elapsed); } }
}
13
Jimmy

.NETソースを実際にチェックする以外に、エリックリッパートは価値があることについて this SO question に関するコメントを提供しました。DateTimeは約30ミリ秒までしか正確ではありません。彼の言葉では、ナノ秒精度でない理由は「正確である必要はない」ということです。

5
Scott Anderson

[〜#〜] msdn [〜#〜] からDateTime.Nowapproximate解像度は、すべてのNTオペレーティングシステムで10ミリ秒です。

実際の精度はハードウェアに依存します。 QueryPerformanceCounter を使用すると、より高い精度を得ることができます。

5
Kevin Montrose

MSDNドキュメントから

このプロパティの解像度は、システムタイマーによって異なります。

また、Windows NT 3.5以降でのおよその解像度は10µmsであると主張しています:)

3
Tomas Vana

このプロパティの解像度は、基になるオペレーティングシステムに依存するシステムタイマーに依存します。 0.5ミリ秒から15ミリ秒の間になる傾向があります。

その結果、ループなどの短い時間間隔でNowプロパティを繰り返し呼び出すと、同じ値が返される場合があります。

MSDNリンク

1
Iman Abidi