2014-11-19 8 views
6

ich zwei Doppelzimmer in .NET bin zu teilen und unter Verwendung des Ergebnisses Objekt ein Enddatum von einem Startdatum durch den Aufruf zu erarbeiten (dtstart vordefiniert):Warum rundet DateTime.AddDays auf die nächste Millisekunde auf?

var dValue = 1500.0/8400.0; 
var dtEnd = dtStart.AddDays(dValue); 

Nach DTEND Inspektion fand ich, dass das Ergebnis nur war genau auf die nächste Millisekunde. Nach dem Nachschlagen fand ich, dass .AddMilliseconds etc. rund um die Nummer und TimeSpan.FromDays eine ähnliche Sache macht. Ich habe mich gefragt, ob es einen Grund gab, warum diese Rundung gemacht wurde, da es scheint, dass der einzige Weg, um den richtigen Wert zu erhalten, darin besteht, .AddTicks zu verwenden?

Als Referenz .AddDays Aufrufe (wobei MillisPerDay = 86400000)

public DateTime AddDays(double value) 
{ 
    return Add(value, MillisPerDay); 
} 

die

private DateTime Add(double value, int scale) 
{ 
    long millis = (long)(value * scale + (value >= 0? 0.5: -0.5)); 
    if (millis <= -MaxMillis || millis >= MaxMillis) 
    throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_AddValue")); 
    return AddTicks(millis * TicksPerMillisecond); 
} 
+0

Das kostet meine ziemlich viel Debugging-Zeit. Bevor ich Audio-bezogenen Code schrieb, berechnete ich, dass die Genauigkeit von Double und 'TimeSpan' ausreicht, um ein bestimmtes Sample eindeutig zu identifizieren. Und dann entschied sich die blöde 'FromSeconds'-Funktion dafür, auf Millisekunden zu runden ... – CodesInChaos

Antwort

2

bearbeiten ruft: Nachdem es vorbei, ich jetzt erkennen, die erste Version meiner Antwort war falsch zu denken.

Hier sind die Kommentare im Quellcode von Microsoft:

// Returns the DateTime resulting from adding a fractional number of 
// xxxxs to this DateTime. The result is computed by rounding the 
// fractional number of xxxxs given by value to the nearest 
// millisecond, and adding that interval to this DateTime. The 
// value argument is permitted to be negative. 

Diese Kommentare auf fünf verschiedenen AddXxxxs (double-Wert) Methoden erscheinen, wobei XXXX = Tage, Stunden, Millisekunden, Minuten und Sekunden.

Beachten Sie, dass dies nur für die Methoden gilt, die einen Gleitkommawert akzeptieren. (Und man kann fragen, ob es eine gute Idee ist, Gleitkommawerte in Datumsberechnungen einzubeziehen - aber das ist ein Thema für einen anderen Tag.)

Jetzt, wie das OP richtig zeigt, nennen diese fünf Methoden das Methode:

// Returns the DateTime resulting from adding a fractional number of 
// time units to this DateTime. 
private DateTime Add(double value, int scale) { 
    long millis = (long)(value * scale + (value >= 0? 0.5: -0.5)); 
    if (millis <= -MaxMillis || millis >= MaxMillis) 
     throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_AddValue")); 
    return AddTicks(millis * TicksPerMillisecond); 
} 

was ist also getan wird, dass der Wert auf die Datetime vor hinzugefügt wird auf die nächste Zahl von Millisekunden gerundet hinzugefügt werden. Aber nicht das Ergebnis - nur der Wert wird hinzugefügt (oder subtrahiert).

Dies ist tatsächlich dokumentiert, zum Beispiel http://msdn.microsoft.com/en-us/library/system.datetime.adddays%28v=vs.110%29.aspx "Der Wert Parameter wird auf die nächste Millisekunde gerundet."

Warum es das weiß ich nicht. Vielleicht haben die Programmierer gedacht, dass wenn Sie Fließkommawerte verwenden, Sie wissen sollten, dass Ihre Werte in der Regel nicht ganz genau sind. Oder sie wollen bis zu einem gewissen Grad Java-Zeiten simulieren, die auf Millisekunden basieren.

+0

Ich wünschte, der ursprüngliche Kodierer der DateTime-Implementierung würde antworten. Wenn sie nicht auf Millisekunden, sondern direkt auf die Anzahl der Ticks pro Tag skaliert würden, würden wir beim Hinzufügen von mehr als 1042,5 Tagen Rundungsfehler bekommen. Diese Zahl stammt aus dem Max-Integer-Bereich, der genau durch ein Double, 2^53 -1, geteilt durch TicksPerDay repräsentiert werden kann. Microsoft verwendet 100-ns-Auflösung, also ist TicksPerDay 24 * 60 * 60 * 1000 * 1000 * 100. Also, rate ich auf Millisekunden, macht das Verhalten ein bisschen leichter vorherzusagen. –

Verwandte Themen