2010-01-26 9 views
74

Ich habe gerade einige unerwartete Verhalten mit DateTime.UtcNow bei einigen Komponententests lief. Wenn Sie DateTime.Now/UtcNow in schneller Folge aufrufen, scheint es, als ob Sie den gleichen Wert für ein länger als erwartetes Zeitintervall zurückgeben, anstatt genauere Millisekunden-Schritte zu erfassen.C# DateTime.Now Genauigkeit

Ich weiß, dass es eine Stoppuhrklasse gibt, die besser für genaue Zeitmessungen geeignet wäre, aber ich war neugierig, ob jemand dieses Verhalten in DateTime erklären könnte? Gibt es eine offizielle Genauigkeit, die für DateTime.Now dokumentiert ist (z. B. präzise innerhalb 50   ms?)? Warum sollte DateTime.Now weniger genau gemacht werden als die meisten CPU-Uhren? Vielleicht ist es nur für die CPU mit dem kleinsten gemeinsamen Nenner ausgelegt?

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(); 
} 
+0

Was ist das Intervall, in dem Sie den gleichen Wert zurück? – ChrisF

+3

Lesen Sie http://StackOverflow.com/Questions/307582/how-frequent-is-DateTime-now-updated-or-is-there-a-more-precise-api-to-get-the –

+0

Als ich lief über Code, ich habe nur 3 eindeutige Werte für Ticks und Millisekunden, und die letzte Stoppuhr Zeit war 147 ms, so scheint es, dass auf meinem Rechner ist es nur präzise um 50ms ... –

Antwort

148

Warum sollte DateTime.Now weniger präzise gemacht werden als die meisten CPU-Uhren?

sollte ein guter Takt beides seine präzise und genaue ; das sind verschieden. Wie der alte Witz sagt, ist eine gestoppte Uhr genau zweimal am Tag genau, eine Uhr, die eine Minute lang ist, ist zu keiner Zeit genau. Aber die eine Minute langsame Uhr ist immer genau auf die nächste Minute, während eine gestoppte Uhr überhaupt keine brauchbare Genauigkeit hat.

Warum sollte die Datetime sein präzise zu sagen, eine Mikrosekunde, wenn es möglicherweise nicht genaue auf die Mikrosekunde sein? Die meisten Menschen haben keine Quelle für offizielle Zeitsignale, die auf die Mikrosekunde genau sind.Daher geben sechs Ziffern nach der Dezimalstelle Präzision, die letzten fünf davon sind Müll wäre liegen.

Denken Sie daran, der Zweck von DateTime ist ein Datum und eine Uhrzeit darstellen. Hochpräzise Timings sind nicht der Zweck von DateTime; Wie Sie bemerken, ist dies der Zweck von StopWatch. Der Zweck von DateTime besteht darin, ein Datum und eine Uhrzeit für Zwecke wie die Anzeige der aktuellen Uhrzeit für den Benutzer, die Berechnung der Anzahl der Tage bis zum nächsten Dienstag usw. darzustellen.

Kurz gesagt, "wie spät ist es?" und "Wie lange hat das gedauert?" sind völlig verschiedene Fragen; Verwenden Sie kein Werkzeug, um eine Frage zu beantworten und die andere zu beantworten.

Danke für die Frage; Das wird einen guten Blogartikel machen! :-)

+2

@Eric Lippert: Raymond Chen hat einen Oldie, aber was ist der Unterschied zwischen "Präzision" und "Genauigkeit"? Http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952. aspx – jason

+1

Ok, guter Punkt über Genauigkeit vs. Genauigkeit. Ich denke, ich kaufe immer noch nicht die Aussage, dass DateTime nicht genau ist, weil "es nicht sein muss". Wenn ich ein transaktionales System habe, und ich möchte für jeden Datensatz eine Datetime markieren, scheint es für mich intuitiv, die DateTime-Klasse zu verwenden, aber es scheint, dass es in .NET genauere/genauere Zeitkomponenten gibt, also warum sollte DateTime sein weniger fähig gemacht. Ich schätze, ich muss noch mehr lesen ... –

+9

OK @Andy, nehme an, du hast ein solches System. Auf einer Maschine markieren Sie eine Transaktion wie am 1. Januar, 12: 34: 30.23498273. Auf einem anderen Computer in Ihrem Cluster markieren Sie eine Transaktion wie am 1. Januar 12: 34: 30.23498456. Welche Transaktion ist zuerst aufgetreten? Wenn Sie nicht wissen, dass die beiden Maschinenuhren innerhalb einer Mikrosekunde synchronisiert sind, haben Sie keine Ahnung, welcher zuerst auftrat. Die zusätzliche Präzision ist * irreführender Müll *. Wenn es nach mir ginge, würden alle DateTimes wie in VBScript auf die nächste Sekunde gerundet. –

2

From MSDN documentation:

Die Auflösung dieser Eigenschaft hängt von den System-Timer.

Sie behaupten auch, dass die ungefähre Auflösung unter Windows NT 3.5 und höher 10   ms ist :)

5

Für das, was es wert ist, kurz eigentlich .NET Quelle Überprüfung bereitgestellt Eric Lippert einen Kommentar zu this SO question sagen, dass DateTime nur auf ca. 30 ms genau ist. Der Grund dafür, dass er in seinen Worten keine Nanosekundengenauigkeit hat, ist, dass es "nicht sein muss".

+2

Und es könnte schlimmer sein. In VBScript rundet die Now() -Funktion das zurückgegebene Ergebnis auf die nächste Sekunde, wobei die Tatsache, dass der zurückgegebene Wert ausreichend genau ist, um genau zu sein, auf die Mikrosekunde zurückzuführen ist. In C# heißt die Struktur DateTime; Es soll ein Datum und eine Zeit für typische nicht-wissenschaftliche Domänen der realen Welt darstellen, wie zum Beispiel wann Ihre Lebensversicherung abläuft oder wie lange sie seit dem letzten Neustart vergangen ist. Es ist nicht für hochpräzise Sub-Sekunden-Timing gedacht. –

13

Die Genauigkeit von DateTime ist etwas spezifisch für das System, auf dem es ausgeführt wird. Die Genauigkeit bezieht sich auf die Geschwindigkeit eines Kontextschalters, der in der Regel bei 15 oder 16   ms liegt. (Auf meinem System ist es tatsächlich etwa 14   ms aus meinen Tests, aber ich habe einige Laptops gesehen, wo es näher an 35-40   ms Genauigkeit.)

Peter Bromberg an article on high precision code timing in C# geschrieben, die in diesem diskutiert.

+1

Die 4 Win7-Maschinen, die ich über die Jahre hatte, hatten alle eine Genauigkeit von etwa 1 ms. Now() sleep (1) Now() führte immer zu einer ~ 1ms Änderung der Datetime, als ich getestet habe. – Bengie

+0

Ich sehe die ~ 1ms Genauigkeit auch. – Timo

2

Von MSDN finden Sie, dass DateTime.Now eine ungefähre Auflösung von 10 Millisekunden auf allen NT-Betriebssystemen hat.

Die tatsächliche Genauigkeit ist hardwareabhängig. Bessere Präzision kann mit QueryPerformanceCounter erreicht werden.

9

würde ich eine präzise Datetime.Now mag :), so dass ich gekocht auf den Punkt:

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); } } 
} 
+1

Ich mag diese Lösung, aber ich war mir nicht sicher, also stellte ich meine eigene Frage (http://stackoverflow.com/q/18257987/270348). Laut Kommentar/Antwort von Servy sollten Sie die Stoppuhr niemals zurücksetzen. – RobSiklos

+1

Vielleicht nicht in deinem Kontext, aber das Zurücksetzen macht in meinem Kontext Sinn - ich stelle nur sicher, dass es fertig ist, bevor das Timing tatsächlich beginnt. – Jimmy

Verwandte Themen