web-dev-qa-db-fra.com

TSQL: Comment convertir l'heure locale en heure UTC? (SQL Server 2008)

Nous avons affaire à une application qui doit gérer des données horaires globales provenant de différents fuseaux horaires et de paramètres d'heure d'été. L'idée est de tout stocker au format UTC en interne et de ne convertir que pour les interfaces utilisateur localisées. SQL Server offre-t-il des mécanismes permettant de gérer les traductions en fonction d'une heure, d'un pays et d'un fuseau horaire?

Cela doit être un problème commun, alors je suis surpris que Google ne trouve rien d’utilisable.

Des pointeurs?

68
BuschnicK

7 ans ont passé et ...
En fait, cette nouvelle fonctionnalité de SQL Server 2016 répond exactement à vos besoins.
Il est appelé AT FUSEAU HORAIRE et il convertit la date en un fuseau horaire spécifié en tenant compte des changements de l'heure d'été (DST).
Plus d'infos ici: https://msdn.Microsoft.com/en-us/library/mt612795.aspx

34
Piotr Owsiak

Cela fonctionne pour les dates qui ont actuellement le même décalage UTC que l'hôte de SQL Server. il ne tient pas compte des changements de l'heure d'été. Remplacez YOUR_DATE Par la date locale à convertir.

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

59
shaig

Quelques-unes de ces réponses vous permettront de comprendre, mais vous ne pouvez pas faire ce que vous essayez de faire avec des dates arbitraires pour SqlServer 2005 et les versions antérieures en raison de l'heure avancée. L’utilisation de la différence entre l’UTC local et l’actuel UTC actuel me donnera le décalage tel qu’il existe aujourd’hui. Je n'ai pas trouvé le moyen de déterminer quelle compensation aurait été pour la date en question.

Cela dit, je sais que SqlServer 2008 fournit de nouvelles fonctions de date pouvant résoudre ce problème, mais les personnes utilisant une version antérieure doivent être conscientes des limitations.

Notre approche consiste à conserver le code UTC et à effectuer la conversion côté client, où nous contrôlons mieux la précision de la conversion.

21
user890155

SQL Server 2008 a un type appelé datetimeoffset. C'est vraiment utile pour ce genre de choses.

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

Vous pouvez ensuite utiliser la fonction SWITCHOFFSET pour le déplacer d’un fuseau horaire à un autre, tout en conservant la même valeur UTC.

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

Rob

14
Rob Farley

Vous pouvez utiliser mon projet prise en charge du fuseau horaire SQL Server pour convertir les fuseaux horaires standard IANA, comme indiqué ici .

UTC to Local est comme ceci:

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

Local to UTC est comme ceci:

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

Les options numériques permettent de contrôler le comportement lorsque les valeurs de l’heure locale sont affectées par l’heure avancée. Celles-ci sont décrites en détail dans la documentation du projet.

14

Voici le code pour convertir une zone DateTime en une autre 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

Remarque : AT TIME ZONEne fonctionne que sur SQL Server 2016 + et l'avantage est qu'il considère automatiquement la lumière du jour lors de la conversion en un fuseau horaire particulier

10
KarthikeyanMlp

J'ai tendance à vouloir utiliser DateTimeOffset pour tout stockage date-heure qui n'est pas lié à un événement local (par exemple: réunion/fête, etc., de 12h à 15h au musée).

Pour obtenir le DTO actuel au format UTC:

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]

REMARQUE: J'utiliserai toujours le temps UTC lors de l'envoi sur le réseau filaire ... Le JS côté client peut facilement se rendre au/à la heure UTC locale. Voir: new Date().toJSON() ...

Le JS suivant gérera l’analyse d’une date UTC/GMT au format ISO8601 en une heure locale.

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;
  };
}
4
Tracker1

Oui, dans une certaine mesure comme détaillé ici .
L’approche que j’ai utilisée (avant 2008) consiste à effectuer la conversion dans la logique métier .NET avant de l’insérer dans la base de données.

3
AdaTheDev

Vous pouvez utiliser la fonction GETUTCDATE () pour obtenir la date et l'heure UTC. Vous pouvez probablement sélectionner la différence entre GETUTCDATE () et GETDATE () et utiliser cette différence pour ajuster vos dates à l'heure UTC.

Mais je suis d'accord avec le message précédent, il est beaucoup plus facile de contrôler le bon datetime dans la couche de gestion (dans .NET, par exemple).

2
Bogdan_Ch