Derzeit haben wir eine Standardmethode für den DateTime
zeitzonenbewussten Umgang mit .NETs: Immer wenn wir eine DateTime
in UTC erstellen (z. B. mit DateTime.UtcNow
) und wenn wir eine anzeigen, konvertieren wir von UTC zurück in die Ortszeit des Benutzers .
Das funktioniert gut, aber ich habe darüber gelesen DateTimeOffset
und wie es die lokale und UTC-Zeit im Objekt selbst erfasst. Die Frage ist also, was wären die Vorteile der Verwendung im DateTimeOffset
Vergleich zu dem, was wir bereits getan haben?
Antworten:
DateTimeOffset
ist eine Darstellung der momentanen Zeit (auch als absolute Zeit bekannt ). Damit meine ich einen Moment in der Zeit, der für alle universell ist (ohne Berücksichtigung von Schaltsekunden oder den relativistischen Effekten der Zeitdilatation ). Eine andere Möglichkeit, die momentane Zeit darzustellen, ist dasDateTime
Wo.Kind
istDateTimeKind.Utc
.Dies unterscheidet sich von der Kalenderzeit (auch als Zivilzeit bezeichnet ), die eine Position im Kalender einer Person darstellt, und es gibt weltweit viele verschiedene Kalender. Wir nennen diese Kalender Zeitzonen . Die Kalenderzeit wird durch ein
DateTime
Wo.Kind
istDateTimeKind.Unspecified
oder dargestelltDateTimeKind.Local
. Und.Local
ist nur sinnvoll in Situationen , in denen Sie ein implizites Verständnis davon, wo der Computer, der das Ergebnis verwendet wird , positioniert. (Zum Beispiel die Workstation eines Benutzers)Warum also
DateTimeOffset
statt einer UTCDateTime
? Es geht nur um Perspektive. Verwenden wir eine Analogie - wir geben vor, Fotografen zu sein.Stellen Sie sich vor, Sie stehen auf einer Kalender-Zeitleiste und richten eine Kamera auf eine Person auf der vor Ihnen liegenden augenblicklichen Zeitleiste. Sie richten Ihre Kamera gemäß den Regeln Ihrer Zeitzone aus - diese ändern sich regelmäßig aufgrund der Sommerzeit oder aufgrund anderer Änderungen an der gesetzlichen Definition Ihrer Zeitzone. (Sie haben keine ruhige Hand, daher ist Ihre Kamera wackelig.)
Die Person, die auf dem Foto steht, sieht den Winkel, aus dem Ihre Kamera stammt. Wenn andere Bilder machen, können sie aus verschiedenen Blickwinkeln sein. Dies ist, was der
Offset
Teil derDateTimeOffset
darstellt.Wenn Sie Ihre Kamera also als "Eastern Time" bezeichnen, zeigen Sie manchmal von -5 und manchmal von -4. Es gibt Kameras auf der ganzen Welt, die alle mit unterschiedlichen Dingen beschriftet sind und aus verschiedenen Winkeln auf dieselbe augenblickliche Zeitachse zeigen. Einige von ihnen befinden sich direkt nebeneinander (oder übereinander). Es reicht also nicht aus, 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 da draußen, die garantiert eine ruhige Hand hat. Es steht auf einem Stativ und ist fest im Boden verankert. Es geht nirgendwo hin. Wir nennen seinen Perspektivwinkel den Nullpunktversatz.
Also - was sagt uns diese Analogie? Es bietet einige intuitive Richtlinien-
Wenn Sie die Zeit relativ zu einem bestimmten Ort darstellen, stellen Sie sie in Kalenderzeit mit a dar
DateTime
. Stellen Sie nur sicher, dass Sie niemals einen Kalender mit einem anderen verwechseln.Unspecified
sollte deine Annahme sein.Local
ist nur nützlich, wenn man von kommtDateTime.Now
. Zum Beispiel könnte ich es bekommenDateTime.Now
und in einer Datenbank speichern - aber wenn ich es abrufe, muss ich davon ausgehen, dass es istUnspecified
. Ich kann mich nicht darauf verlassen, dass mein lokaler Kalender derselbe ist, aus dem er ursprünglich stammt.Wenn Sie immer sicher sein müssen, stellen Sie sicher, dass Sie die momentane Zeit darstellen. Verwenden
DateTimeOffset
Sie diese Option , um sie durchzusetzen, oder verwenden Sie UTCDateTime
gemäß Konvention.Wenn Sie einen Moment der augenblicklichen Zeit verfolgen müssen, aber auch wissen möchten: "Wann hat der Benutzer gedacht, dass er in seinem lokalen Kalender steht?" - dann müssen Sie a verwenden
DateTimeOffset
. Dies ist beispielsweise für Zeitnehmungssysteme sehr wichtig - sowohl aus technischen als auch aus rechtlichen Gründen.Wenn Sie jemals eine zuvor aufgezeichnete Änderung ändern
DateTimeOffset
müssen, verfügen Sie nicht über genügend Informationen allein im Offset, um sicherzustellen, dass der neue Offset für den Benutzer weiterhin relevant ist. Sie müssen auch eine Zeitzonen-ID speichern (denken Sie - ich benötige den Namen dieser Kamera, damit ich ein neues Bild aufnehmen kann, auch wenn sich die Position geändert hat).Es sollte auch darauf hingewiesen werden, dass Noda Time eine dafür vorgesehene Darstellung
ZonedDateTime
hat, während die .Net-Basisklassenbibliothek nichts Ähnliches hat. Sie müssten sowohl einenDateTimeOffset
als auch einenTimeZoneInfo.Id
Wert speichern .Gelegentlich möchten Sie eine Kalenderzeit darstellen, die lokal für "denjenigen ist, der sie betrachtet" ist. Zum Beispiel bei der Definition dessen, was heute bedeutet. Heute ist immer Mitternacht bis Mitternacht, aber diese repräsentieren eine nahezu unendliche Anzahl überlappender Bereiche auf der augenblicklichen Zeitachse. (In der Praxis haben wir eine endliche Anzahl von Zeitzonen, aber Sie können Offsets bis zum Häkchen ausdrücken.) Stellen Sie in diesen Situationen sicher, dass Sie verstehen, wie Sie entweder das "Wer fragt?" Begrenzen können. Fragen Sie bis zu einer einzelnen Zeitzone oder übersetzen Sie sie gegebenenfalls zurück in die momentane Zeit.
Hier sind ein paar andere Kleinigkeiten
DateTimeOffset
, die diese Analogie stützen, und einige Tipps, um sie klar zu halten:Wenn Sie zwei
DateTimeOffset
Werte vergleichen , werden diese vor dem Vergleich zunächst auf Nullversatz normiert. Mit anderen Worten,2012-01-01T00:00:00+00:00
und2012-01-01T02:00:00+02:00
beziehen sich auf den gleichen augenblicklichen Moment und sind daher äquivalent.Wenn Sie einen Komponententest durchführen und den Versatz sicher sein müssen, testen Sie sowohl den
DateTimeOffset
Wert als auch die.Offset
Eigenschaft separat.In das .NET-Framework ist eine implizite Einwegkonvertierung integriert, mit der Sie a an einen
DateTime
beliebigenDateTimeOffset
Parameter oder eine beliebige Variable übergeben können. Dabei die es.Kind
ankommt . Wenn Sie eine UTC-Art übergeben, wird diese mit einem Nullpunktversatz übertragen. Wenn Sie jedoch eine.Local
oder übergeben.Unspecified
, wird davon ausgegangen, dass sie lokal ist . Das Framework sagt im Grunde: "Nun, Sie haben mich gebeten, die Kalenderzeit in die Momentanzeit umzuwandeln, aber ich habe keine Ahnung, woher diese stammt, also werde ich nur den lokalen Kalender verwenden." Dies ist ein großes Problem, wenn Sie ein nicht angegebenes GerätDateTime
auf einen Computer mit einer anderen Zeitzone laden . (IMHO - das sollte eine Ausnahme auslösen - tut es aber nicht.)Schamloser Stecker:
Viele Leute haben mir mitgeteilt, dass sie diese Analogie äußerst wertvoll finden, deshalb habe ich sie in meinen Pluralsight-Kurs, Datums- und Zeitgrundlagen, aufgenommen . Eine schrittweise Anleitung zur Kameraanalogie finden Sie im zweiten Modul "Context Matters" im Clip "Calendar Time vs. Instantaneous Time".
quelle
DateTimeOffset
in C # haben, sollten Sie dies auf einemDATETIMEOFFSET
in SQL Server beibehalten .DATETIME2
oder nurDATETIME
(abhängig vom erforderlichen Bereich) sind für reguläreDateTime
Werte in Ordnung . Ja - Sie können eine Ortszeit aus einer beliebigen Paarung von Zeitzone + dto oder utc auflösen. Der Unterschied besteht darin, dass Sie die Regeln immer mit jeder Auflösung berechnen möchten oder sie vorberechnen möchten. In vielen Fällen (manchmal aus rechtlichen Gründen) ist ein DTO die bessere Wahl.DateTimeOffset.Now
auf dem Server sagen , erhalten Sie tatsächlich den Offset des Servers. Der Punkt ist, dass derDateTimeOffset
Typ diesen Versatz beibehalten kann. Sie können dies genauso einfach auf dem Client tun, an den Server senden, und dann würde Ihr Server den Offset des Clients kennen.Von Microsoft:
Quelle: "Auswahl zwischen DateTime, DateTimeOffset, TimeSpan und TimeZoneInfo" , MSDN
Wir verwenden
DateTimeOffset
für fast alles, da unsere Anwendung bestimmte Zeitpunkte behandelt (z. B. als ein Datensatz erstellt / aktualisiert wurde). Als Randnotiz verwenden wir auchDATETIMEOFFSET
in SQL Server 2008.Ich sehe es
DateTime
als nützlich an, wenn Sie sich nur mit Datumsangaben, nur mit Uhrzeiten oder generisch mit beiden befassen möchten. Wenn Sie beispielsweise einen Alarm haben, den Sie jeden Tag um 7 Uhr morgens auslösen möchten, können Sie diesen in einerDateTime
VerwendungDateTimeKind
von speichern,Unspecified
da er unabhängig von der Sommerzeit um 7 Uhr morgens ausgelöst werden soll. Wenn Sie jedoch den Verlauf von Alarmereignissen darstellen möchten, würden Sie verwendenDateTimeOffset
.Seien Sie vorsichtig, wenn Sie eine Mischung aus
DateTimeOffset
undDateTime
insbesondere beim Zuweisen und Vergleichen zwischen den Typen verwenden. Vergleichen Sie außerdem nurDateTime
Instanzen, die identisch sind,DateTimeKind
daDateTime
beim Vergleich der Zeitzonenversatz ignoriert wird.quelle
Kind
wird, dass sie gleich sind -, könnte der Vergleich fehlerhaft sein. Wenn beide Seiten habenDateTimeKind.Unspecified
, wissen Sie nicht wirklich, dass sie aus derselben Zeitzone stammen. Wenn beide Seiten sindDateTimeKind.Local
, die meisten Vergleiche fein sein werden, aber man konnte immer noch Fehler haben ist die eine Seite in der lokalen Zeitzone nicht eindeutig ist. Wirklich nurDateTimeKind.Utc
Vergleiche sind kinderleicht und ja,DateTimeOffset
wird normalerweise bevorzugt. (Prost!)DateTime kann nur zwei unterschiedliche Zeiten speichern, die Ortszeit und die UTC. Die Kind- Eigenschaft gibt an, welche.
DateTimeOffset erweitert dies, indem es Ortszeiten von überall auf der Welt speichern kann. Es speichert auch den Versatz zwischen dieser Ortszeit und UTC. Beachten Sie, dass DateTime dies nur tun kann, wenn Sie Ihrer Klasse ein zusätzliches Mitglied hinzufügen, um diesen UTC-Offset zu speichern. Oder arbeiten Sie immer nur mit UTC. Was an sich schon eine gute Idee ist.
quelle
Es gibt einige Stellen, an denen
DateTimeOffset
Sinn macht. Eine ist, wenn Sie mit wiederkehrenden Ereignissen und Sommerzeit zu tun haben. Nehmen wir an, ich möchte jeden Tag um 9 Uhr einen Wecker stellen. Wenn ich die Regel "Als UTC speichern, als Ortszeit anzeigen" verwende, wird der Alarm zu einer anderen Zeit ausgelöst, wenn die Sommerzeit wirksam ist.Es gibt wahrscheinlich andere, aber das obige Beispiel ist tatsächlich eines, auf das ich in der Vergangenheit
DateTimeOffset
gestoßen bin (dies war vor dem Hinzufügen zur BCL - meine damalige Lösung bestand darin, die Zeit explizit in der lokalen Zeitzone zu speichern und zu speichern die Zeitzoneninformationen daneben: im Grunde genommen, wasDateTimeOffset
intern funktioniert).quelle
Der wichtigste Unterschied besteht darin, dass DateTime keine Zeitzoneninformationen speichert, während DateTimeOffset dies tut.
Obwohl DateTime zwischen UTC und Local unterscheidet, ist absolut kein expliziter Zeitzonenversatz damit verbunden. Wenn Sie irgendeine Art von Serialisierung oder Konvertierung durchführen, wird die Zeitzone des Servers verwendet. Selbst wenn Sie manuell eine Ortszeit erstellen, indem Sie Minuten hinzufügen, um eine UTC-Zeit zu versetzen, können Sie im Serialisierungsschritt dennoch ein Bit erhalten, da (aufgrund des Fehlens eines expliziten Versatzes in DateTime) der Zeitzonenversatz des Servers verwendet wird.
Wenn Sie beispielsweise einen DateTime-Wert mit Kind = Local mithilfe von 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) nichts mit Ihrer DateTime oder einem Versatz zu tun hat, den Sie zur Berechnung verwendet haben. Es handelt sich lediglich um den Zeitzonenversatz des Servers.In der Zwischenzeit enthält DateTimeOffset den Offset explizit. Möglicherweise enthält es nicht den Namen der Zeitzone, aber zumindest den Versatz. Wenn Sie ihn serialisieren, erhalten Sie den explizit enthaltenen Versatz in Ihrem Wert anstelle der Ortszeit des Servers.
quelle
The most important distinction is that DateTime does not store time zone information, while DateTimeOffset does.
Dieser Code von Microsoft erklärt alles:
quelle
Die meisten Antworten sind gut, aber ich dachte darüber nach, weitere Links zu MSDN hinzuzufügen, um weitere Informationen zu erhalten
quelle
Ein Hauptunterschied besteht darin, dass
DateTimeOffset
in Verbindung mitTimeZoneInfo
der Konvertierung in Ortszeiten in anderen als den aktuellen Zeitzonen verwendet werden kann.Dies ist nützlich für eine Serveranwendung (z. B. ASP.NET), auf die Benutzer in verschiedenen Zeitzonen zugreifen.
quelle
Die einzige negative Seite von DateTimeOffset, die ich sehe, ist, dass Microsoft (von Natur aus) "vergessen" hat, es in seiner XmlSerializer-Klasse zu unterstützen. Inzwischen wurde es jedoch der XmlConvert-Dienstprogrammklasse hinzugefügt.
XmlConvert.ToDateTimeOffset
XmlConvert.ToString
Ich sage, verwenden Sie DateTimeOffset und TimeZoneInfo wegen aller Vorteile. Seien Sie vorsichtig, wenn Sie Entitäten erstellen, die in oder aus XML serialisiert werden oder werden können (dann alle Geschäftsobjekte).
quelle