it-swarm.com.de

Wie gehe ich mit TimeZone in SQL Server richtig um?

Mein lokaler Entwicklungsserver befindet sich im Nahen Osten, mein Produktionsserver jedoch in Großbritannien.

Ich muss dem Benutzer das Datum in seiner Zeitzone anzeigen. Wenn sich ein Benutzer beispielsweise in Saudi-Arabien befindet, muss ich die Uhrzeit gemäß dem Saudi-Arabien-Format anzeigen.

Sollte ich eine neue Datenbanktabelle mit dem Namen TimeZone erstellen und die Zeit in UTC speichern?

39
user960567

Dafür gibt es leider keine schnelle Lösung. Die Internationalisierung einer Anwendung sollte Teil der allerersten Entwurfsdiskussionen sein, da sie sich wirklich auf viele verschiedene Bereiche bezieht, einschließlich Datums-/Zeitvergleiche und Ausgabeformatierung.

Um auf dem richtigen Weg zu sein, ist es wichtig, die Zeitzoneninformationen mit der Zeit zu speichern. Mit anderen Worten, zu erkennen, dass das Datum/die Uhrzeit 20130407 14:50 ist bedeutungslos ohne entweder (a) einschließlich des dann aktuellen UTC-Offsets der Zeitzone(Anmerkung 1)oder (b) Sicherstellen, dass die gesamte Logik, die diese Werte zuerst einfügt, in einen bestimmten festen Versatz konvertiert wird (höchstwahrscheinlich 0). Ohne eines dieser Dinge sind zwei gegebene Zeitwerte unvergleichlich und die Daten sind korrupt. (Die letztere Methode spielt mit dem Feuer(Anmerkung 2), Apropos; tu das nicht.)

In SQL Server 2008+ können Sie den Versatz mit der Zeit direkt speichern, indem Sie den Datentyp datetimeoffset verwenden. (Der Vollständigkeit halber habe ich 2005 und früher eine zweite Spalte hinzugefügt, um den dann aktuellen UTC-Versatzwert (in Minuten) zu speichern.)

Dies macht es für eine Desktop-Anwendung einfach, da diese Plattformen normalerweise über Mechanismen verfügen, um ein Datum/eine Uhrzeit + eine Zeitzone automatisch in eine Ortszeit zu konvertieren und dann für die Ausgabe zu formatieren, basierend auf den regionalen Einstellungen des Benutzers.

Für das Web, das eine inhärent getrennte Architektur ist, ist es selbst bei ordnungsgemäß eingerichteten Back-End-Daten komplexer, da Sie Informationen über den Client benötigen, um die Konvertierung und/oder Formatierung durchführen zu können. Dies erfolgt normalerweise über Benutzereinstellungen (die Anwendung konvertiert/formatiert Dinge vor der Ausgabe) oder zeigt einfach Dinge mit demselben festen Format und Zeitzonenversatz für alle an (was die Stack Exchange-Plattform derzeit tut).

Sie können sehen, dass wenn die Back-End-Daten nicht richtig eingerichtet sind, es sehr schnell kompliziert und hackig wird. Ich würde nicht empfehlen, einen dieser Wege zu beschreiten, da Sie später mehr Probleme haben werden.

Anmerkung 1:

Der UTC-Versatz einer Zeitzone ist nicht festgelegt: Berücksichtigen Sie die Sommerzeit, wenn der UTC-Versatz einer Zone um plus oder minus eine Stunde variiert. Auch die Sommerzeitdaten der Zonen variieren regelmäßig. Verwenden Sie also datetimeoffset (oder eine Zusammenstellung von local time und UTC offset at that time) führt zu maximaler Informationswiederherstellung.

Anmerkung 2:

Es geht darum, Dateneingaben zu steuern. Es gibt zwar keine narrensichere Möglichkeit, eingehende Werte zu validieren, es ist jedoch besser, einen einfachen Standard durchzusetzen, der keine Berechnungen umfasst. Wenn eine öffentliche API einen Datentyp erwartet, der einen Offset enthält, ist diese Anforderung für den Aufrufer klar.

Wenn dies nicht der Fall war, muss sich der Anrufer auf die Dokumentation verlassen (wenn er sie liest) oder die Berechnung wird falsch durchgeführt usw. Es gibt weniger Fehler-/Fehlermodi, wenn ein Offset erforderlich ist, insbesondere für ein verteiltes System ( oder auch nur Web/Datenbank auf separaten Servern (wie hier).

Das Speichern des Versatzes tötet sowieso zwei Fliegen mit einer Klappe; und selbst wenn dies nicht erforderlich ist jetzt, stellt es die Möglichkeit später bei Bedarf zur Verfügung. Zwar nimmt es mehr Speicherplatz in Anspruch, aber ich denke, es ist den Kompromiss wert, da die Daten verloren gehen, wenn sie überhaupt nicht aufgezeichnet werden.

51
Jon Seigel

Ich habe eine umfassende Lösung für die Zeitzonenkonvertierung in SQL Server entwickelt. Siehe SQL Server-Zeitzonenunterstützung auf GitHub .

Konvertierungen zwischen Zeitzonen und von und nach UTC, einschließlich Sommerzeit, werden ordnungsgemäß verarbeitet.

Das Konzept ähnelt der in der Antwort von adss beschriebenen "T-SQL Toolbox" -Lösung, verwendet jedoch die gängigeren IANA/Olson/TZDB-Zeitzonen anstelle der von Microsoft und enthält Dienstprogramme, mit denen die Daten als neue Versionen von beibehalten werden TZDB kommt raus.

Anwendungsbeispiel (zur Beantwortung des OP):

SELECT Tzdb.UtcToLocal(sysutcdatetime(), 'Asia/Riyadh') as CurrentTimeInSaudiArabia

Weitere APIs und detaillierte Erklärungen finden Sie unter Readme auf GitHub .

Beachten Sie außerdem, dass dies eine UDF-basierte Lösung ist und nicht auf Leistung als Hauptziel ausgelegt ist. Es wäre immer noch besser, wenn diese Funktionalität in SQL Server integriert wäre, ähnlich wie das CONVERT_TZ Funktion existiert in Oracle und MySQL.

15

Ich habe das Projekt „T-SQL Toolbox“ entwickelt und veröffentlicht auf Codeplex , um allen zu helfen, die mit der Behandlung von Datum und Uhrzeit in SQL Server zu kämpfen haben. Es ist Open Source und völlig kostenlos zu benutzen.

Es bietet einfache UDFs zur Konvertierung von Datum und Uhrzeit mit einfachem T-SQL und zusätzlichen Konfigurationstabellen.

In Ihrem Beispiel können Sie das folgende Beispiel verwenden:

SELECT [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] (
    'GMT Standard Time', -- the original timezone in which your datetime is stored
    'Middle East Standard Time', -- the target timezone for your user
    '2014-03-30 01:55:00' -- the original datetime you want to convert
)

Dies gibt den konvertierten Datum/Uhrzeit-Wert für Ihren Benutzer zurück.

Eine Liste aller unterstützten Zeitzonen finden Sie in der Tabelle "DateTimeUtil.Timezone", die auch in der T-SQL Toolbox-Datenbank enthalten ist.

7
adss

SQL Server hat ab 2005 Änderungen vorgenommen, bei denen die interne Zeitzone in UTC gespeichert wird. Dies war hauptsächlich auf Geo-Replikation und HA-Projektoren zurückzuführen, die den Protokollversand beinhalteten, und die Speicherung der Protokollversandzeiten in verschiedenen Zeitzonen machte es der alten Methode unmöglich, sie wiederherzustellen.

Durch das interne Speichern aller Daten in UTC-Zeit konnte SQL Server global gut funktionieren. Dies ist einer der Gründe, warum die Sommerzeit in Windows ein Problem darstellt, da andere MS-Produkte wie Outlook das Datum und die Uhrzeit auch intern als UTC speichern und einen Offset erstellen, der gepatcht werden muss.

Ich arbeite in einem Unternehmen, in dem Tausende von Servern (allerdings keine MS SQL-Server, sondern alle Arten von Servern) auf der ganzen Welt verteilt sind. Wenn wir nicht ausdrücklich alles auf UTC erzwingen würden, wären wir alle verrückt geworden sehr schnell.

6
Ali Razeghi

Möglicherweise fehlt mir etwas Offensichtliches, aber wenn Sie das Datum nur in der Zeitzone und im Sprachformat des Benutzers anzeigen möchten, ist es am einfachsten, die Daten immer in UTC in der Datenbank zu speichern und die Clientanwendung von UTC in lokal konvertieren zu lassen Zeitzone und verwenden Sie die regionalen Einstellungen des Benutzers, um das Datum entsprechend zu formatieren.

1
20c