2014-11-19 11 views
6

jestem dzieląc dwa dwuosobowe w .NET i przy użyciu obiektu rezultatu, który ma wypracować datę z datą rozpoczęcia przez wywołanie (dtstart jest predefiniowany):Dlaczego DateTime.AddDays zaokrągla do najbliższej milisekundy?

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

Po zbadaniu dtend Okazało się, że wynik był tylko z dokładnością do najbliższej milisekundy. Po sprawdzeniu tego znalazłem, że .AddMilliseconds itp. Wokół numeru i TimeSpan.FromDays robi podobną rzecz. Zastanawiam się, czy był jakiś powód, dla którego to zaokrąglenie zostało wykonane, ponieważ wydaje się, że jedynym sposobem uzyskania poprawnej wartości jest użycie .AddTicks?

Dla .AddDays referencyjne połączeń (gdzie MillisPerDay = 86400000)

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

który nazywa

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

Kosztowało to trochę czasu na debugowanie. Przed napisaniem jakiegoś kodu związanego z dźwiękiem obliczyłem, że dokładność zarówno podwójnej, jak i "TimeSpan" wystarcza, aby jednoznacznie zidentyfikować konkretną próbkę. I wtedy głupia funkcja "FromSeconds" zdecydowała się zaokrąglić do milisekund ... – CodesInChaos

Odpowiedz

2

Edycja: Po myśląc o niczym, teraz zrealizować pierwszą wersję moją odpowiedzią było źle.

Oto komentarze w kodzie źródłowym Microsoftu:

// 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. 

Te komentarze pojawiają się na pięciu różnych AddXxxxs (podwójna wartość) metod, gdzie xxxx = dni, godzin, milisekundy, minutach i sekundach.

Należy zauważyć, że dotyczy to tylko metod akceptujących wartość zmiennoprzecinkową. (Można też zapytać, czy warto włączyć wartości zmiennoprzecinkowe w obliczeniach daty - ale to jest temat na inny dzień.)

Teraz, jak prawidłowo wskazuje OP, wszystkie te pięć metod nazywają to metoda:

// 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); 
} 

Więc co się robi jest to, że wartość dodawana do DateTime jest zaokrąglana do najbliższej liczby milisekundy przed dodaniem. Ale nie wynik - tylko wartość dodawana (lub odejmowana).

To jest faktycznie udokumentowane, na przykład http://msdn.microsoft.com/en-us/library/system.datetime.adddays%28v=vs.110%29.aspx "Parametr wartości jest zaokrąglany do najbliższej milisekundy."

Dlaczego to robi, nie wiem. Może programiści doszli do wniosku, że jeśli używasz wartości zmiennoprzecinkowych, powinieneś wiedzieć, że twoje wartości zazwyczaj nie są całkowicie dokładne. A może chcą symulować do pewnego stopnia czasy w stylu Java, które są oparte na milisekundach.

+0

Chciałbym odpowiedzieć na oryginalny koder implementacji DateTime. Jeśli nie skalowaliby się do milisekund, ale bezpośrednio do liczby kleszczy dziennie, myślę, że uzyskalibyśmy błędy zaokrąglania przy dodawaniu więcej niż 1042,5 dnia. Liczba ta pochodzi z maksymalnego zakresu liczb całkowitych, który może być dokładnie odwzorowany jako double, 2^53 -1, podzielony przez TicksPerDay. Microsoft używa rozdzielczości 100-ns, więc TicksPerDay to 24 * 60 * 60 * 1000 * 1000 * 100. Zgaduję więc, że zaokrąglanie do milisekund sprawia, że ​​zachowanie jest łatwiejsze do przewidzenia. –

Powiązane problemy