2010-09-16 16 views
7

Ich konvertiere ein DateTime nach OADate. Ich hatte erwartet, beim Konvertieren der OADate genau das gleiche DateTime zu bekommen, aber jetzt hat es nur eine Auflösung von Millisekunden und ist daher anders..NET DateTime, unterschiedliche Auflösung beim Konvertieren von und nach OADate?

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 

Ticks von a: 634202170964319073

Ticks von b: 634202170964310000

Die OADate double: 40437,290467951389

Was ist der Grund dafür? Die Auflösung von DateTime ist eindeutig gut genug.

Antwort

3

Die statische Methode von ToOADate genannt teilt eindeutig die Zecken von 10000 und dann speichert das Ergebnis in einem langen, wodurch jede Unter Millisekunden info Entfernen

Weiß jemand, wo die Spezifikationen des OADate Formats zu finden?

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

Nicht genau Angaben, aber das ist eine Lektüre wert: http://blogs.msdn.com/b/ericlippert/archive/2003/09/16/eric-s-complete-guide-to-vt-date.aspx –

+0

Danke, es scheint eine Menge Geschichte hinter diesem Datumsformat zu stehen ... –

1

Wahrscheinlich hat etwas mit der Genauigkeit der Doppel, nicht die DateTime zu tun.

+0

Das konvertierte Doppel ist 40437.290467951389, sieht ziemlich präzise aus, aber Sie könnten Recht haben. – Ezombort

+0

Ja, das Double wäre genau genug, aber aufgrund der Art und Weise, wie double gespeichert ist, gibt es keine exakte Darstellung des datetime als double. – Carvellis

+0

@Ezombort Es sieht nur wegen des Umrechnungsfaktors zwischen Sekunden und Tagen genau aus. Wenn Sie das von Ihnen genannte "double" mit "24.0 * 60.0 * 60.0" multiplizieren, sehen Sie nur drei Dezimalstellen. Ein "beliebiges" "double" dieser Größe zeigt fünf Dezimalstellen (oder sieben Dezimalstellen, wenn Sie mit '.ToString (" R ")' anzeigen). So wird die volle Genauigkeit eines 'double' nicht genutzt. Siehe meine neue Antwort. –

10

Ich denke, das ist eine ausgezeichnete Frage. (Ich entdeckte es einfach.)

Es sei denn, Sie sind mit Terminen ganz in der Nähe des Jahres 1900 ein DateTime Betrieb wird eine höhere Präzision als ein OA Datum. Aber aus irgendeinem obskuren Grund, die Autoren der DateTime Struktur nur Liebe auf die nächste ganze Millisekunde abgeschnitten, wenn sie zwischen DateTime und etwas anderes zu konvertieren. Unnötig zu sagen, dass dies ohne guten Grund eine Menge Präzision wegwirft.

Hier ist ein Work-around:

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

Nun lassen Sie uns (aus Ihrer Frage) betrachten die DateTime gegeben durch:

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

Die Genauigkeit jeder DateTime beträgt 0,1 us.

in der Nähe von Datum und Zeit, die wir schätzen, ist die Präzision eines OA Datum:

Math.Pow(2.0, -37.0) Tage oder circa 0.6286 us

Wir schließen daraus, dass in dieser Region ein DateTime ist genauer als ein OA-Datum von (knapp über) einem Faktor sechs.

Lassen Sie uns ourDT-double konvertieren Jetzt mit meinem Erweiterungsmethode oben

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

, wenn Sie ourOADate zurück zu einem DateTime mit der statischen FromOADatePrecise Methode oben konvertieren, erhalten Sie

2010-09-16T06:58:16.4319072 (geschrieben mit "O" Format)

Im Vergleich zum Original sehen wir, dass der Genauigkeitsverlust in diesem Fall 0,1 μs beträgt. Wir erwarten, dass der Genauigkeitsverlust innerhalb von ± 0,4 μs liegt, da dieses Intervall eine Länge von 0,8 μs hat, was mit den zuvor erwähnten 0,6286 μs vergleichbar ist.

Wenn wir den anderen Weg gehen, beginnend mit einem double einen OA Datum darstellen, nicht zu nahe an das Jahr 1900, und erste Verwendung FromOADatePrecise und dannToOADatePrecise, dann bekommen wir wieder ein double, und weil Die Präzision des Intermediates DateTime ist der eines OA-Datums überlegen, wir erwarten in diesem Fall einen perfekten Round-Trip. Wenn Sie andererseits die BCL-Methoden FromOADate und ToOADate in der gleichen Reihenfolge verwenden, ist es sehr unwahrscheinlich, eine gute Hin- und Rückfahrt zu bekommen (es sei denn, die von uns begonnene double hat eine ganz spezielle Form).

+1

Und es war früher schlimmer. Vor Jahren habe ich einen Fehler gefunden, bei dem Daten manchmal auf die nächste Millisekunde falsch gerundet wurden, und es könnte möglicherweise einen Fehler von bis zu zwei Tagen verursachen. Zum Glück denke ich, dass das irgendwann behoben wurde. –

Verwandte Themen