2009-07-30 3 views
58

Wir haben es mit einer Anwendung zu tun, die globale Zeitdaten aus verschiedenen Zeitzonen und Sommerzeiteinstellungen verarbeiten muss. Die Idee besteht darin, alles intern im UTC-Format zu speichern und nur für die lokalisierten Benutzeroberflächen hin und her zu konvertieren. Bietet der SQL Server Mechanismen für den Umgang mit den Übersetzungen für eine bestimmte Zeit, ein Land und eine Zeitzone?TSQL: Wie konvertiert man lokale Zeit in UTC? (SQL Server 2008)

Das muss ein allgemeines Problem sein, also bin ich überrascht, dass Google nichts brauchbares aufdrehen würde.

Irgendwelche Zeiger?

+0

Ich habe meinen mssql-Server mit einem mysql-Server verbunden. Ich frage mich, ob es möglich ist, mysql CONVERT_TZ (Zeit, srczone, dstzone) auf die Abfragen auszuführen :-) Seltsam diese Funktion fehlt; Es ist in Linux integriert. –

+0

@BuschnicK Siehe meine Antwort unten. Eigentlich glaube ich, dass du es akzeptieren kannst, auch wenn es für andere einfacher ist, es zu finden. –

Antwort

21

7 Jahre vergangen und ...
tatsächlich gibt es diese neue SQL Server 2016-Funktion, die genau das tut, was Sie brauchen.
Es heißt AT TIME ZONE und konvertiert das Datum in eine bestimmte Zeitzone unter Berücksichtigung der Änderungen der Sommerzeit (DST).
Mehr Infos hier: https://msdn.microsoft.com/en-us/library/mt612795.aspx

+8

Nicht mehr daran arbeiten - nicht bei diesem Projekt, nicht bei SQL Server, nicht bei der gleichen Firma und nicht einmal im selben Land ;-) So wird es mir nicht helfen, aber ich Werde diese Frage jetzt beantworten. – BuschnicK

+0

@BuschnicK Ja, ich denke, aber ich bin hier auf der Suche nach einer Lösung für das gleiche Problem, also habe ich beschlossen, eine Abfrage jetzt, dass es eine echte Lösung ist: D –

+1

Die Frage ist für SQL Server 2008. Bitte aktualisieren Sie die Frage, ob Sie diese Antwort akzeptieren. Thx – Robert

3

Ja, zu einem gewissen Grad wie detailliert here.
Der Ansatz, den ich (vor 2008) verwendet habe, ist die Konvertierung in der .NET-Geschäftslogik vor dem Einfügen in die DB.

2

Sie können GETUTCDATE() Funktion verwenden UTC Datumzeit zu bekommen Wahrscheinlich können Sie Unterschied zwischen GETUTCDATE() und GETDATE() und verwenden diese Differenz wählen Sie Ihre Reisedaten ein, um UTC

Aber ich stimme mit früheren Mitteilung an ajust, dass es viel einfacher ist, das richtige Datum in der Business-Schicht zu steuern (zB in .NET).

+12

Nein! Der Unterschied hängt vom genauen Datum ab. Es kommt auf die Sommerzeit an. – usr

+3

Berücksichtigt keine Sommerzeit. Ich habe solche Lösungen schon seit einiger Zeit benutzt und es hat große Probleme verursacht. Sie müssen bestimmen, ob das Datum, mit dem Sie vergleichen, in DST ist. –

13

SQL Server 2008 hat einen Typ namens datetimeoffset. Es ist wirklich nützlich für diese Art von Sachen.

http://msdn.microsoft.com/en-us/library/bb630289.aspx

Dann können Sie die Funktion SWITCHOFFSET verwenden Sie es von einer Zeitzone in einer anderen zu bewegen, aber immer noch den gleichen UTC Wert zu halten.

http://msdn.microsoft.com/en-us/library/bb677244.aspx

Rob

+3

SWITCHOFFSET berücksichtigt keine Sommerzeit, daher ist es nur in bestimmten Situationen nützlich. – robocat

+1

Nein. Aber die Frage war, dass man mit der Umstellung auf die gewünschte Zeitzone umgehen konnte. –

+0

Aus der Frage "verschiedene Zeitzonen und Sommerzeiteinstellungen". Auch wir suchen nach einer Lösung für die lokale Zeit. Ihr Vorschlag löst das Thema der Sommerzeit nicht, oder? – robocat

51

Diese für Daten arbeiten, die zur Zeit die gleichen UTC Offset wie SQL Server-Host; Änderungen bei der Sommerzeit werden nicht berücksichtigt. Ersetzen Sie YOUR_DATE durch das lokale Datum für die Konvertierung.

SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);

+2

Danke, das ist eine gute Idee, aber es funktioniert nur für genau eine Zeitzone - die lokale Maschine. Wir müssen es aber für beliebige Zeitzonen verwenden ... – BuschnicK

+0

clever, aber ja, pass auf Zeitzonen auf. – Krip

+39

Dies berücksichtigt keine Sommerzeit –

21

Während einige dieser Antworten finden Sie im Baseballstadion bekommen, können Sie nicht tun, was Sie versuchen, mit beliebigen Daten für SQL Server 2005 zu tun und früher wegen der Sommerzeit. Die Verwendung der Differenz zwischen der aktuellen lokalen und der aktuellen UTC gibt mir den Offset, wie er heute existiert. Ich habe keinen Weg gefunden zu bestimmen, wie hoch der Offset für das fragliche Datum gewesen wäre.

Das sagte, ich weiß, dass SqlServer 2008 einige neue Datumsfunktionen bietet, die dieses Problem beheben können, aber Leute, die eine frühere Version verwenden, müssen sich der Einschränkungen bewusst sein.

Unser Ansatz besteht darin, UTC beizubehalten und die Konvertierung auf der Clientseite durchzuführen, wo wir mehr Kontrolle über die Genauigkeit der Konvertierung haben.

+2

es ist traurig, dass dies die Antwort ist! –

4

Ich neige dazu, mit DateTimeOffset für alle Datum-Zeit-Speicher, die nicht auf ein lokales Ereignis (dh Treffen/Party, etc., 12 pm-3pm im Museum) verbunden ist.

Um den aktuellen DTO als UTC erhalten:

DECLARE @utcNow DATETIMEOFFSET = CONVERT(DATETIMEOFFSET, SYSUTCDATETIME()) 
DECLARE @utcToday DATE = CONVERT(DATE, @utcNow); 
DECLARE @utcTomorrow DATE = DATEADD(D, 1, @utcNow); 
SELECT @utcToday [today] 
     ,@utcTomorrow [tomorrow] 
     ,@utcNow [utcNow]

HINWEIS: Ich werde immer UTC verwenden, wenn sie über den Draht ... clientseitige JS kann das Senden an/von lokalen UTC leicht.Siehe: new Date().toJSON() ...

Der folgende JS wird die Analyse eines UTC/GMT-Datums im ISO8601-Format zu einer lokalen Datetime verarbeiten.

if (typeof Date.fromISOString != 'function') { 
    //method to handle conversion from an ISO-8601 style string to a Date object 
    // Date.fromISOString("2009-07-03T16:09:45Z") 
    // Fri Jul 03 2009 09:09:45 GMT-0700 
    Date.fromISOString = function(input) { 
    var date = new Date(input); //EcmaScript5 includes ISO-8601 style parsing 
    if (!isNaN(date)) return date; 

    //early shorting of invalid input 
    if (typeof input !== "string" || input.length < 10 || input.length > 40) return null; 

    var iso8601Format = /^(\d{4})-(\d{2})-(\d{2})((([T ](\d{2}):(\d{2})(:(\d{2})(\.(\d{1,12}))?)?)?)?)?([Zz]|([-+])(\d{2})\:?(\d{2}))?$/; 

    //normalize input 
    var input = input.toString().replace(/^\s+/,'').replace(/\s+$/,''); 

    if (!iso8601Format.test(input)) 
     return null; //invalid format 

    var d = input.match(iso8601Format); 
    var offset = 0; 

    date = new Date(+d[1], +d[2]-1, +d[3], +d[7] || 0, +d[8] || 0, +d[10] || 0, Math.round(+("0." + (d[12] || 0)) * 1000)); 

    //use specified offset 
    if (d[13] == 'Z') offset = 0-date.getTimezoneOffset(); 
    else if (d[13]) offset = ((parseInt(d[15],10) * 60) + (parseInt(d[16],10)) * ((d[14] == '-') ? 1 : -1)) - date.getTimezoneOffset(); 

    date.setTime(date.getTime() + (offset * 60000)); 

    if (date.getTime() <= new Date(-62135571600000).getTime()) // CLR DateTime.MinValue 
     return null; 

    return date; 
    }; 
}
+0

+1 Ich habe auch zu DateTimeOffset gewechselt. Es vermeidet eine Reihe von Problemen mit UTC + lokalen Konvertierungen. Aus ähnlichen Gründen empfehle ich jedoch, Werte mit einem Offset über die Leitung (über JSON) zu senden. – user2864740

+0

Als Anmerkung mache ich, was Sie tun * genau * andersherum. Für DateTimes, die an ein lokales Ereignis gebunden sind, speichere ich ein DateTimeOffset. Für eine DateTime, die nicht an ein lokales Ereignis gebunden ist, speichere ich eine DateTime in UTC. Ersteres hat zwei relevante Datenpunkte (wann ist es in der lokalen Zeit und welche Ortszeit ist das), letzteres nur eins (wenn es ist) – Martijn

+0

@Martijn Aber die Zeitzone gibt Ihnen nicht den Ort, und Sie müssen gespeichert werden Jedenfalls irgendwie. – Tracker1

-1

Verwendungsbeispiel:

SELECT 
    Getdate=GETDATE() 
    ,SysDateTimeOffset=SYSDATETIMEOFFSET() 
    ,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0) 
    ,GetutcDate=GETUTCDATE() 
GO 

Returns:

Getdate SysDateTimeOffset SWITCHOFFSET GetutcDate 
2013-12-06 15:54:55.373 2013-12-06 15:54:55.3765498 -08:00 2013-12-06 23:54:55.3765498 +00:00 2013-12-06 23:54:55.373 
10

Sie können meine SQL Server Time Zone Support Projekt zu konvertieren zwischen IANA Standardzeitzonen, as listed here verwenden.

UTC Local ist wie folgt:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles') 

Local UTC ist wie folgt:

SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1) 

Die numerischen Optionen sind Kennzeichen für das Verhalten zu steuern, wenn die lokalen Zeitwert von Tageslicht betroffen sind Zeit sparen. Diese sind in der Projektdokumentation ausführlich beschrieben.

+0

Wie man ... dieses Projekt von Matt ist großartig und erfordert nicht die CLR. Matt verdient viel Anerkennung für diese +100 – buckley

2

Hier ist der Code eine Zone DateTime

DECLARE @UTCDateTime DATETIME = GETUTCDATE(); 
    DECLARE @ConvertedZoneDateTime DATETIME; 

    -- 'UTC' to 'India Standard Time' DATETIME 
    SET @ConvertedZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time' 
    SELECT @UTCDateTime AS UTCDATE,@ConvertedZoneDateTime AS IndiaStandardTime 

    -- 'India Standard Time' to 'UTC' DATETIME 
    SET @UTCDateTime = @ConvertedZoneDateTime AT TIME ZONE 'India Standard Time' AT TIME ZONE 'UTC' 
    SELECT @ConvertedZoneDateTime AS IndiaStandardTime,@UTCDateTime AS UTCDATE 

HinweisDateTime in eine andere Zone zu konvertieren: Diese (AT TIME ZONE) arbeiten nur SQL Server 2016+ und diese Vorteil ist automatisch Berücksichtigung von Tageslicht während der Umwandlung in bestimmte Zeitzone

Verwandte Themen