Geben Sie die Zeitzone von datetime an, ohne den Wert zu ändern

8

Ich frage mich, wie man die Zeitzone eines DateTime-Objekts ändern kann, ohne den Wert tatsächlich zu ändern. Hier ist der Hintergrund ...

Ich habe eine ASP.NET MVC-Site auf AppHarbor gehostet und der Server hat seine Zeit auf UTC eingestellt. Wenn ich ein Formular von meiner Site übergebe, das einen Datetime-Wert enthält, sagen wir 17.09.2013, 4:00 Uhr, kommt es auf den Server mit diesem Wert. Aber dann, wenn ich das tue:

%Vor%

... es hält es fälschlicherweise als die selbe Zeit (4 Uhr), weil der Server bereits in der UTC-Zeit ist. Nach dem Konvertieren in UTC und dem Speichern in der Datenbank ist der Datenbankwert 2013-09-17 04: 00: 00.000, wenn es wirklich 2013-09-17 08: 00: 00.000 sein sollte, da der Browser auf EST ist. Ich hatte gehofft, dass nach dem Senden des Formulars und dem Übergeben der Werte an die Controller-Aktion die Zeitzone von DateTime auf den Browser (EST) und nicht auf den Server-Host (UTC) gesetzt würde, was aber nicht passiert ist.

In jedem Fall stecke ich jetzt mit einem DateTime-Objekt fest, das den korrekten Datums- / Uhrzeitwert aber die falsche Zeitzone enthält, sodass ich es nicht korrekt in UTC umwandeln kann. Ich speichere die Zeitzone jedes Benutzers. Wenn es also eine Möglichkeit gibt, die Zeitzone für das DateTime-Objekt festzulegen, ohne den Wert tatsächlich zu ändern (TimeZoneInfo.ConvertTime kann nicht ausgeführt werden, weil der Wert geändert wird), könnte ich das haben der richtige Datum / Uhrzeit-Wert UND die richtige Zeitzone, dann könnte ich sicher Date.ToUniversalTime tun. Davon abgesehen habe ich nur gesehen, wie man die Art einer DateTime ändert, nicht die TimeZone, ohne ihren tatsächlichen Wert zu ändern.

Irgendwelche Ideen?

    
Justin 17.09.2013, 01:52
quelle

1 Antwort

10

Eigentlich macht es genau das, was Sie von ihm verlangt haben. Aus der Sicht des Servers haben Sie eine "unspezifizierte" DateTime übergeben. Mit anderen Worten, nur Jahr, Monat, usw., ohne irgendeinen Kontext. Wenn Sie sich die Eigenschaft .Kind ansehen, werden Sie sehen, dass es tatsächlich DateTimeKind.Unspecified ist.

Wenn Sie .ToUniversalTime() für eine nicht angegebene Art von DateTime aufrufen, übernimmt .NET den Kontext der lokalen Zeitzone des Computers, auf dem der Code ausgeführt wird. Sie können mehr über diese in der Dokumentation hier lesen. Da Ihr Server auf UTC eingestellt ist, führen alle drei Arten unabhängig von der Art der Eingabe zum selben Ergebnis. Grundsätzlich ist es ein No-Op.

Sie haben jetzt gesagt, dass Sie die Uhrzeit für die Zeitzone des Benutzers angeben möchten. Leider sind das Informationen, die der Server nicht hat. Es gibt keinen magischen HTTP-Header, der Zeitzonendetails enthält.

Es gibt jedoch Möglichkeiten, diesen Effekt zu erzielen, und Sie haben einige Optionen.

JavaScript-Methode

Dies ist wahrscheinlich die einfachste Option, erfordert aber JavaScript.

  • Nehmen Sie die lokale Eingabe von Datum und Uhrzeit von Ihrem Benutzer und parsen Sie sie in eine JavaScript Date -Klasse.
    • Zum leichteren Analysieren sollten Sie stattdessen ein moment aus der moment.js -Bibliothek verwenden.
  • Erhalte das UTC-Datum und die UTC-Zeit von Date oder moment und gib es an deinen Server weiter.
    • Dies ist in JavaScript relativ einfach, daher erspare ich Ihnen die Details.
    • Es gibt viele Formate, die Sie weitergeben können, aber der bevorzugte Weg ist ein ISO8601-Zeitstempel. Beispiel: 2013-09-17T08:00:00.000Z
  • Vergessen Sie nicht das Z am Ende. Das bedeutet, dass die Zeit in UTC ist.
  • Da es Ihnen als UTC übergeben wurde, können Sie es einfach ohne Konvertierung speichern.
  • Beim Abrufen wird UTC erneut an den Browser übergeben, in ein Date oder ein moment mit JavaScript geladen und dann das lokale Datum und die Uhrzeit ausgegeben.
  • Ich empfehle Ihnen dringend, moment.js zu versuchen, wenn Sie diesen Ansatz verfolgen. Es kann ohne es gemacht werden, aber das kann viel komplizierter und fehleranfällig sein.

.NET-Methode, die Windows-Zeitzonen verwendet

Wenn Sie JavaScript nicht aufrufen, müssen Sie den Benutzer nach seiner Zeitzone fragen. Dies kann in einer größeren Anwendung, z. B. auf der Profilseite des Benutzers, gut funktionieren.

  • Verwenden Sie TimeZoneInfo.GetSystemTimeZones , um eine Dropdown-Liste zu erstellen.
    • Verwenden Sie für jedes TimeZoneInfo -Element in der Liste .Id für den Wert und% .DisplayName für den Text.
  • Dann können Sie diesen Wert verwenden, wenn Sie die Zeit konvertieren möchten.

    %Vor%
  • Dies funktioniert mit Windows-Zeitzonen, die eine Microsoft-Erstellung sind, und einige Nachteile haben. Im Zeitzonen-Tag-Wiki können Sie über einige ihrer Mängel nachlesen.

.NET-Methode, die IANA-Zeitzonen verwendet

Wenn Sie die Standard-IANA-Zeitzonen wie America/New_York oder Europe/London verwenden möchten, können Sie eine Bibliothek wie Noda Time . Es bietet eine viel bessere API für das Arbeiten mit Datum und Uhrzeit als das integrierte Framework. Es gibt ein bisschen eine Lernkurve, aber wenn Sie etwas Kompliziertes machen, ist es die Mühe wert. Als Beispiel:

%Vor%


Über die Sommerzeit

Unabhängig davon, welche dieser drei Ansätze Sie wählen, müssen Sie mit den Problemen umgehen, die durch die Sommerzeit entstehen. Jedes dieser Beispiele zeigt einen "nachsichtigen" Ansatz, bei dem, wenn die von Ihnen angegebene lokale Zeit mehrdeutig oder ungültig ist, eine Regel befolgt wird, sodass Sie immer noch einen gültigen Zeitpunkt haben. Sie können dies direkt mit dem Noda Time-Ansatz sehen, wenn ich AtLeniently aufgerufen habe. Aber es kommt auch bei den anderen vor - es ist nur implizit. In JavaScript können die Regeln je nach Browser variieren. Erwarten Sie daher keine konsistenten Ergebnisse.

Abhängig davon, welche Art von Daten Sie sammeln, können Sie entscheiden, dass es vollkommen akzeptabel ist, eine solche Annahme zu treffen. Aber in vielen Fällen ist es nicht angemessen anzunehmen. In diesem Fall müssen Sie Ihren Benutzer entweder warnen, dass die Eingabezeit ungültig ist, oder ihn fragen, welche der zwei nicht eindeutigen Zeiten gemeint sind.

In .Net können Sie dies mit TimeZoneInfo.IsInvalidTime überprüfen und TimeZoneInfo.IsAmbiguousTime .

Ein Beispiel für die Funktionsweise der Sommerzeit finden Sie hier . In dem "Spring-forward" -Übergang ist eine Zeit während des Übergangs ungültig.In dem "Fallback" -Übergang ist eine Zeit während des Übergangs mehrdeutig - das heißt, sie könnte entweder vor oder nach dem Übergang stattgefunden haben.

    
Matt Johnson 17.09.2013, 05:29
quelle