Wie gehe ich mit TimeZone in SQL Server richtig um?

34

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

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

Soll ich eine neue Datenbanktabelle mit dem Namen TimeZone erstellen und die Uhrzeit in UTC speichern?

user960567
quelle
Konvertieren effektiv Termine zwischen UTC und Local (dh. PST) Zeit in SQL 2005 http://stackoverflow.com/questions/24797/effectively-converting-dates-between-utc-and-local-ie-pst-time-in- SQL-2005
Mehdi
Handelt es sich um eine Webanwendung oder eine Desktopanwendung oder ...? Wie dies implementiert wird, hängt stark vom Client-Bereitstellungsmechanismus ab, da das, was Sie benötigen, von der Client-Seite abhängt.
Jon Seigel
Dieses Web sowie native Mobile. Ja, dies wirkt sich auf verschiedene Clients unterschiedlich aus.
user960567
1
Bei Ihrer Frage geht es anscheinend nicht nur um die Datenbank selbst, sondern auch um die Anwendungsentwicklung. Diese Stapelüberlauf-Frage ist dann ein Muss für Sie: Sommerzeit und bewährte Methoden für die Zeitzone
Gan

Antworten:

48

Leider gibt es dafür keine schnelle Lösung. Die Internationalisierung einer Anwendung sollte Teil der allerersten Designdiskussionen sein, da sie den Kern vieler verschiedener Bereiche betrifft, einschließlich Datums- / Uhrzeitvergleiche und Ausgabeformatierung.

Auf jeden Fall ist es wichtig, die Zeitzoneninformationen mit der Zeit zu speichern, um den Überblick über Doing It Right zu behalten . Mit anderen Worten realisieren, dass das Datum / Zeit 20130407 14:50ist sinnlos , ohne entweder (a) mit der dann aktuellen UTC der Zeitzone versetzt (Anmerkung 1) , oder (b) sichergestellt wird, dass alle Logik dieser Werte zuerst wandelt in einem bestimmten festgelegten Offset Einfügen ( höchstwahrscheinlich 0). Ohne diese beiden Dinge sind zwei angegebene Zeitwerte nicht vergleichbar und die Daten sind fehlerhaft . (Die letztere Methode spielt übrigens mit dem Feuer (Anmerkung 2) ; tun Sie das nicht.)

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

Dies erleichtert eine Desktop-Anwendung, da diese Plattformen normalerweise über Mechanismen verfügen, mit denen Datum / Zeit + Zeitzone automatisch in eine Ortszeit konvertiert und dann entsprechend den regionalen Einstellungen des Benutzers für die Ausgabe formatiert werden.

Für das Web, bei dem es sich um eine von Natur aus getrennte Architektur handelt, ist es auch bei ordnungsgemäß eingerichteten Back-End-Daten komplexer, da Sie Informationen zum Client benötigen, um die Konvertierung und / oder Formatierung durchführen zu können. Dies erfolgt in der Regel über Benutzereinstellungen (die Anwendung konvertiert / formatiert Dinge vor der Ausgabe) oder einfach durch Anzeigen von Dingen mit demselben festen Format und Zeitzonenversatz für alle (wie dies derzeit auf der Stack Exchange-Plattform der Fall ist).

Sie können feststellen, dass die Einrichtung der Back-End-Daten sehr schnell kompliziert und schwierig wird. Ich würde nicht empfehlen, einen dieser Pfade zu beschreiten, da Sie später einfach 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. Die Verwendung von datetimeoffset(oder einer Kombination aus local timeund UTC offset at that time) führt zu einer maximalen Wiederherstellung von Informationen.

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 zu erzwingen, 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 ist, muss sich der Aufrufer 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 der Fall).

Das Speichern des Offsets tötet ohnehin zwei Fliegen mit einer Klappe; und selbst wenn das jetzt nicht benötigt wird , wird die möglichkeit später bei bedarf zur verfügung gestellt. Zwar nimmt es mehr Speicherplatz in Anspruch, aber ich denke, es lohnt sich, dies in Kauf zu nehmen, da die Daten verloren gehen, wenn sie überhaupt nicht aufgezeichnet werden.

Jon Seigel
quelle
3
So wie ich es verstehe, ist ein Versatz nicht dasselbe wie eine Zeitzone ... Zeiten, die in Datum / Uhrzeit-Versatz gespeichert sind, verlieren Informationen wie die Sommerzeit- Erkennung
Peter McEvoy
1
@PeterMcEvoy DST hat hier keine Relevanz. datetimeoffsetbedeutet "Dies ist die Ortszeit des Benutzers / Computers, zu der das Ereignis aufgetreten ist" - wir müssen nicht wissen, ob die Sommerzeit wirksam war oder nicht, da der angegebene UTC-Offset immer vorhanden ist (eingebettet in den datetimeoffsetWert).
Dai
12

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

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

Es ähnelt im Konzept 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 ausführliche Erklärungen finden Sie in der Readme-Datei auf GitHub .

Beachten Sie außerdem, dass dies eine UDF-basierte Lösung ist, die nicht auf Leistung als primäres Ziel ausgelegt ist. Es wäre immer noch besser, wenn diese Funktionalität in SQL Server integriert wäre, ähnlich wie die CONVERT_TZFunktion in Oracle und MySQL vorhanden ist.

Matt Johnson-Pint
quelle
6

SQL Server nahm ab 2005 Änderungen vor, bei denen die interne Zeitzone in UTC gespeichert wird. Dies war hauptsächlich auf die Geo-Replikation und HA-Projektoren zurückzuführen, die den Protokollversand umfassten, und da die Protokollversandzeiten in verschiedenen Zeitzonen gespeichert waren, war es für die alte Methode unmöglich, sie wiederherzustellen.

Wenn Sie also alles intern in UTC-Zeit speichern, funktioniert SQL Server global einwandfrei. Dies ist einer der Gründe, warum die Sommerzeit in Windows ein Problem ist, 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 nicht MS SQL Server, sondern alle Arten von Servern) auf der ganzen Welt verteilt sind, und wenn wir nicht ausdrücklich alles auf UTC-Basis erzwingen würden, würden wir alle verrückt werden sehr schnell.

Ali Razeghi
quelle
5

Ich habe das „T-SQL Toolbox“ -Projekt für Codeplex entwickelt und veröffentlicht , um allen zu helfen, die mit der Verarbeitung 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 für die Datums- und Uhrzeitkonvertierung unter Verwendung von einfachem T-SQL mit 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
)

Dadurch wird der konvertierte Datums- / Uhrzeitwert für Ihren Benutzer zurückgegeben.

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

adss
quelle
Ein solches Toolkit scheint für einen Entwickler eine große Hilfe zu sein. Eine Skalarfunktion ist jedoch eine Blackbox für das Abfrageoptimierungsprogramm. Wenn ich Ihre Funktion auf eine Spalte anwende, werden die von Ihnen erwähnten Konfigurationstabellen so oft aufgerufen, wie Zeilen in der Ergebnismenge vorhanden sind (vorausgesetzt, ich verwende die Funktion nur in der SELECT-Klausel). In Bezug auf die Leistung scheint das keine gute Perspektive zu sein. Ich habe Ihr Toolkit jedoch nicht wirklich getestet, daher kann ich nicht sicher sagen, dass dies nur ein allgemeines Anliegen ist, das auf dem basiert, was ich weiß.
Andriy M
Andriy, klar, du hast Recht in Bezug auf die Leistung. Die UDF-Abfragetabellen sind nicht für Massendatenoperationen vorgesehen, sondern für eine einfache Verwendung. Trotzdem können sie auf meinem Rechner bis zu 100.000 Datensätze verarbeiten.
adss
2
Wenn in seinem Anwendungsfall mehr Datensätze verarbeitet werden müssen und es auf die Leistung ankommt, sollten Sie besser daran denken, vorberechnete Daten beizubehalten. Aber selbst dann können diese UDFs dazu beitragen, die Datenzeitwerte in den erforderlichen Zeitzonen beizubehalten.
adss
Aus meiner Sicht geht es bei diesem Problem nicht um Leistung, sondern nur darum, die grundlegenden Funktionen zu nutzen. Um in der Lage zu sein, genaue Informationen aus einer Abfrage zurückzugeben, ist das erste, was Sie tun müssen. Das Ausarbeiten einer temporären Tabelle zum Zwischenspeichern von Dingen und das anschließende Verweisen auf diese Tabelle in der Abfrage oder das Verarbeiten dieser Tabelle zum Verbessern der Leistung ist zweitrangig.
Aktion Dan
1

Ich vermisse vielleicht etwas Offensichtliches, aber wenn Sie nur das Datum in der Zeitzone und im Sprachformat des Benutzers anzeigen möchten, ist es am einfachsten, die Datumsangaben immer in UTC in der Datenbank zu speichern und die Client-Anwendung von UTC nach lokal konvertieren zu lassen Verwenden Sie die regionalen Benutzereinstellungen, um das Datum entsprechend zu formatieren.

20c
quelle