1085 Stimmen

DateTime vs. DateTimeOffset

Was ist der Unterschied zwischen einer DateTime und eine DateTimeOffset und wann sollte eine solche verwendet werden?


Derzeit haben wir eine Standardmethode für den Umgang mit .NET DateTime s in einer TimeZone-gerechten Weise: Wann immer wir eine DateTime wir machen es in UTC (z. B. mit DateTime.UtcNow ), und jedes Mal, wenn wir eine anzeigen, konvertieren wir von UTC in die Ortszeit des Benutzers zurück.

Das funktioniert gut, aber ich habe gelesen, dass DateTimeOffset und wie es die Orts- und UTC-Zeit im Objekt selbst erfasst.

0 Stimmen

Wenn es um die Lagerung geht, stackoverflow.com/questions/4715620/ ist ebenfalls interessant.

3 Stimmen

Für Neugierige ist vielleicht auch interessant Die Speicherung von UTC ist kein Patentrezept

1674voto

Matt Johnson-Pint Punkte 212496

DateTimeOffset ist eine Darstellung von augenblickliche Zeit (auch bekannt als absolute Zeit ). Damit meine ich einen Moment in der Zeit, der für alle gilt (ohne Berücksichtigung von Schaltsekunden oder die relativistischen Effekte von Zeitdilatation ). Eine andere Möglichkeit, die momentane Zeit darzustellen, ist die Verwendung eines DateTime wobei .Kind es DateTimeKind.Utc .

Dies unterscheidet sich von Kalenderzeit (auch bekannt als Zivilzeit ), d. h. eine Position im Kalender einer Person, und es gibt viele verschiedene Kalender auf der ganzen Welt. Wir nennen diese Kalender Zeitzonen . Die Kalenderzeit wird durch ein DateTime wobei .Kind es DateTimeKind.Unspecified , oder DateTimeKind.Local . Und .Local ist nur in Szenarien sinnvoll, in denen man weiß, wo sich der Computer befindet, der das Ergebnis verwendet. (Zum Beispiel der Arbeitsplatz eines Benutzers)

Warum also DateTimeOffset anstelle einer UTC DateTime ? Es ist alles eine Frage der Perspektive. Nehmen wir eine Analogie: Wir tun so, als wären wir Fotografen.

Stellen Sie sich vor, Sie stehen auf einer Kalenderzeitleiste und richten eine Kamera auf eine Person, die sich auf der vor Ihnen liegenden Zeitleiste befindet. Sie richten Ihre Kamera nach den Regeln Ihrer Zeitzone aus - die sich aufgrund der Sommerzeit oder anderer Änderungen der gesetzlichen Definition Ihrer Zeitzone regelmäßig ändern. (Sie haben keine ruhige Hand, also ist Ihre Kamera verwackelt.)

Die Person, die auf dem Foto steht, würde den Winkel sehen, aus dem Ihre Kamera kam. Wenn andere Personen Fotos machten, könnten diese aus unterschiedlichen Winkeln stammen. Das ist es, was die Offset Teil des DateTimeOffset vertritt.

Wenn Sie also Ihre Kamera mit "Eastern Time" beschriften, zeigen Sie manchmal auf -5 und manchmal auf -4. Überall auf der Welt gibt es Kameras, die alle unterschiedlich beschriftet sind und alle aus verschiedenen Blickwinkeln auf dieselbe Zeitlinie zeigen. Einige von ihnen befinden sich direkt nebeneinander (oder übereinander), so dass es nicht ausreicht, nur den Versatz zu kennen, um festzustellen, auf welche Zeitzone sich die Zeit bezieht.

Und was ist mit UTC? Nun, es ist die einzige Kamera auf dem Markt, die garantiert eine ruhige Hand hat. Sie steht auf einem Stativ, das fest im Boden verankert ist. Sie wird nirgendwo hingehen. Wir nennen ihren Blickwinkel die Nullpunktverschiebung.

Instantaneous Time vs Calendar Time Visualization

Was sagt uns also diese Analogie? Sie liefert einige intuitive Leitlinien.

  • Wenn Sie die Zeit relativ zu einem bestimmten Ort darstellen wollen, stellen Sie sie in Kalenderzeit mit einem DateTime . Achten Sie nur darauf, dass Sie niemals einen Kalender mit einem anderen verwechseln. Unspecified sollte Ihre Annahme sein. Local ist nur nützlich, wenn sie von DateTime.Now . Ich könnte zum Beispiel Folgendes bekommen DateTime.Now und speichere sie in einer Datenbank - aber wenn ich sie abrufe, muss ich davon ausgehen, dass sie Unspecified . Ich kann mich nicht darauf verlassen, dass mein lokaler Kalender derselbe ist, dem er ursprünglich entnommen wurde.

  • Wenn Sie sich immer auf den Zeitpunkt verlassen müssen, sollten Sie sicherstellen, dass Sie die unmittelbare Zeit darstellen. Verwenden Sie DateTimeOffset um sie durchzusetzen, oder verwenden Sie UTC DateTime durch Konvention.

  • Wenn Sie einen Moment der augenblicklichen Zeit verfolgen müssen, aber auch wissen wollen, "Welche Zeit hat der Benutzer in seinem lokalen Kalender gesehen?" - dann müssen Sie muss verwenden eine DateTimeOffset . Dies ist z. B. für Zeiterfassungssysteme sehr wichtig - sowohl aus technischen als auch aus rechtlichen Gründen.

  • Wenn Sie eine bereits aufgezeichnete Datei ändern müssen DateTimeOffset - Sie haben nicht genügend Informationen im Offset allein, um sicherzustellen, dass der neue Offset für den Benutzer noch relevant ist. Sie müssen auch eine Zeitzonenkennung speichern (denken Sie daran, dass ich den Namen der Kamera brauche, damit ich ein neues Bild aufnehmen kann, auch wenn sich die Position geändert hat).

    Es sollte auch darauf hingewiesen werden, dass Noda Zeit hat eine Darstellung namens ZonedDateTime für diese Aufgabe, während die .Net-Basisklassenbibliothek nichts Vergleichbares bietet. Sie müssten sowohl eine DateTimeOffset und eine TimeZoneInfo.Id Wert.

  • Gelegentlich möchten Sie eine Kalenderzeit darstellen, die für denjenigen, der sie betrachtet, lokal ist. Zum Beispiel, wenn Sie definieren, was heute bedeutet. Heute ist immer Mitternacht bis Mitternacht, aber das sind nahezu unendlich viele sich überschneidende Bereiche auf der momentanen Zeitachse. (In der Praxis gibt es eine endliche Anzahl von Zeitzonen, aber man kann die Abstände bis auf den Tick genau ausdrücken.) Stellen Sie also sicher, dass Sie in diesen Situationen wissen, wie Sie entweder die Frage "Wer fragt?" auf eine einzige Zeitzone beschränken oder wie Sie sie gegebenenfalls in die unmittelbare Zeit zurückübersetzen können.

Hier sind noch ein paar andere Kleinigkeiten über DateTimeOffset die diese Analogie untermauern, und einige Tipps, wie man es richtig macht:

  • Wenn Sie zwei DateTimeOffset Werte, werden sie vor dem Vergleich zunächst auf einen Offset von Null normiert. Mit anderen Worten, 2012-01-01T00:00:00+00:00 y 2012-01-01T02:00:00+02:00 beziehen sich auf denselben Moment und sind daher gleichwertig.

  • Wenn Sie Unit-Tests durchführen und sicher sein wollen, dass der Offset stimmt, testen Sie beide el DateTimeOffset Wert, und der .Offset Eigentum getrennt.

  • In das .Net-Framework ist eine einseitige implizite Konvertierung eingebaut, mit der Sie eine DateTime in jede DateTimeOffset Parameter oder Variable. Wenn Sie dies tun, die .Kind Angelegenheiten . Wenn Sie eine UTC-Art übergeben, wird sie mit einem Null-Offset übertragen, aber wenn Sie entweder .Local o .Unspecified wird angenommen, dass es sich um . . Das Framework sagt im Grunde: "Du hast mich gebeten, die Kalenderzeit in die aktuelle Zeit zu konvertieren, aber ich habe keine Ahnung, woher das kommt, also werde ich einfach den lokalen Kalender verwenden. Das ist ein riesiges Problem, wenn Sie eine nicht spezifizierte DateTime auf einem Computer mit einer anderen Zeitzone. (IMHO - das sollte eine Ausnahme auslösen - tut es aber nicht.)

Unverschämter Versuch:

Viele Menschen haben mir mitgeteilt, dass sie diese Analogie äußerst wertvoll finden, weshalb ich sie in meinen Pluralsight-Kurs aufgenommen habe, Grundlagen zu Datum und Uhrzeit . Eine schrittweise Erklärung der Kameraanalogie finden Sie im zweiten Modul, "Context Matters", im Clip "Calendar Time vs. Instantaneous Time".

484voto

Clay Punkte 9785

Von Microsoft:

Diese Verwendungszwecke für DateTimeOffset-Werte sind viel häufiger als die für DateTime-Werte. Daher sollte DateTimeOffset als Standard-Datums- und Zeittyp für die Anwendungsentwicklung angesehen werden.

Quelle: <a href="https://learn.microsoft.com/en-us/dotnet/standard/datetime/choosing-between-datetime" rel="noreferrer">"Auswahl zwischen DateTime, DateTimeOffset, TimeSpan und TimeZoneInfo" </a>, <em>MSDN</em>

Wir verwenden DateTimeOffset für fast alles, da sich unsere Anwendung mit bestimmten Zeitpunkten befasst (z. B. wann ein Datensatz erstellt/aktualisiert wurde). Nebenbei bemerkt, verwenden wir DATETIMEOFFSET auch in SQL Server 2008.

Ich sehe DateTime als nützlich, wenn Sie nur mit Datumsangaben, nur mit Zeitangaben oder mit beidem in einem generischen Sinne arbeiten wollen. Wenn Sie zum Beispiel einen Alarm haben, der jeden Tag um 7 Uhr morgens losgehen soll, können Sie diesen in einer DateTime unter Verwendung eines DateTimeKind von Unspecified weil Sie wollen, dass es unabhängig von der Sommerzeit um 7 Uhr morgens losgeht. Wenn Sie jedoch die Historie der Alarmereignisse darstellen möchten, würden Sie Folgendes verwenden DateTimeOffset .

Seien Sie vorsichtig bei der Verwendung einer Mischung aus DateTimeOffset y DateTime insbesondere bei der Zuordnung und dem Vergleich zwischen den Typen. Vergleichen Sie außerdem nur DateTime Instanzen, die identisch sind DateTimeKind denn DateTime ignoriert beim Vergleich die Zeitzonenverschiebung.

128voto

Hans Passant Punkte 894572

DateTime kann nur zwei verschiedene Zeiten speichern, die Ortszeit und UTC. Die Freundlich Eigenschaft zeigt an, welche.

DateTimeOffset erweitert dies, indem es in der Lage ist, lokale Zeiten von überall auf der Welt zu speichern. Es speichert auch die Versatz zwischen dieser Ortszeit und UTC. Beachten Sie, dass DateTime dies nicht kann, es sei denn, Sie fügen Ihrer Klasse ein zusätzliches Mitglied hinzu, um den UTC-Offset zu speichern. Oder immer nur mit UTC arbeiten. Was an sich eine gute Idee ist, nebenbei bemerkt.

47voto

Mojtaba Punkte 1939

Dieser Teil des Codes aus Microsoft erklärt alles:

// Find difference between Date.Now and Date.UtcNow
  date1 = DateTime.Now;
  date2 = DateTime.UtcNow;
  difference = date1 - date2;
  Console.WriteLine("{0} - {1} = {2}", date1, date2, difference);

  // Find difference between Now and UtcNow using DateTimeOffset
  dateOffset1 = DateTimeOffset.Now;
  dateOffset2 = DateTimeOffset.UtcNow;
  difference = dateOffset1 - dateOffset2;
  Console.WriteLine("{0} - {1} = {2}", 
                    dateOffset1, dateOffset2, difference);
  // If run in the Pacific Standard time zone on 4/2/2007, the example
  // displays the following output to the console:
  //    4/2/2007 7:23:57 PM - 4/3/2007 2:23:57 AM = -07:00:00
  //    4/2/2007 7:23:57 PM -07:00 - 4/3/2007 2:23:57 AM +00:00 = 00:00:00

37voto

Triynko Punkte 18016

Der wichtigste Unterschied ist, dass DateTime keine Zeitzoneninformationen speichert, während DateTimeOffset dies tut.

Obwohl DateTime zwischen UTC und Local unterscheidet, gibt es absolut keinen expliziten Zeitzonen-Offset, der damit verbunden ist. Wenn Sie irgendeine Art von Serialisierung oder Konvertierung durchführen, wird die Zeitzone des Servers verwendet. Selbst wenn Sie manuell eine lokale Zeit durch Hinzufügen von Minuten zum Offset einer UTC-Zeit erstellen, kann es bei der Serialisierung zu Problemen kommen, da (aufgrund des Fehlens eines expliziten Offsets in DateTime) der Offset der Zeitzone des Servers verwendet wird.

Wenn Sie beispielsweise einen DateTime-Wert mit Kind=Local mit Json.Net und einem ISO-Datumsformat serialisieren, erhalten Sie eine Zeichenfolge wie 2015-08-05T07:00:00-04 . Beachten Sie, dass der letzte Teil (-04) hatte nichts mit Ihrem DateTime oder Offset Sie verwendet, um es zu berechnen ... es ist nur rein der Server-Zeitzone Offset zu tun.

In DateTimeOffset ist der Offset explizit enthalten. Er enthält zwar nicht den Namen der Zeitzone, aber zumindest den Offset, und wenn Sie ihn serialisieren, erhalten Sie den explizit enthaltenen Offset in Ihrem Wert anstelle der zufälligen Ortszeit des Servers.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X