2017-09-27 2 views
2

Cette question est un suivi de cette question. J'ai une colonne d'heure UTC et je veux convertir en l'heure locale actuelle (Central Time Zone or America/Chicago). J'ai essayé d'utiliser la fonction de la réponse @Ron Smith, qui est la fonction [dbo].[fn_UTC_to_DST].Heure UTC au fuseau horaire local (heure du Centre) Conversion MS SQL Server

Dans cette fonction, il a besoin de deux arguments tels que l'heure UTC et le décalage. Je saisis les deux comme ceci,

SELECT dbo.fn_UTC_to_DST([time(UTC)],5) as Date 
FROM tbl 

Comme nous sommes en mode Day Light Saving, j'utilise 5 comme offset. Ma sortie ressemble à ceci,

2017-09-27 20:55:00.000 
2017-09-27 20:56:00.000 
2017-09-27 20:57:00.000 
2017-09-27 20:58:00.000 
... 

Ce qui devrait être (heure centrale),

2017-09-27 09:55:00.000 
2017-09-27 09:56:00.000 
2017-09-27 09:57:00.000 
2017-09-27 09:58:00.000 
... 

Alors, je l'ai changé la fonction de @Ron Smith comme celui-ci,

CREATE FUNCTION [dbo].[fn_UTC_to_DST] 
(
    @UTC datetime, 
    @StandardOffset int 
) 
RETURNS datetime 
AS 
BEGIN 
declare 
    @DST datetime, 
    @SSM datetime, -- Second Sunday in March 
    @FSN datetime -- First Sunday in November 

-- get DST Range 
set @SSM = datename(year,@UTC) + '0314' 
set @SSM = dateadd(hour,-5,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM)) -- Changed from 2 to -5 
set @FSN = datename(year,@UTC) + '1107' 
set @FSN = dateadd(second,-6,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN))) -- changed from 1 to -6 

-- add an hour to @StandardOffset if @UTC is in DST range 
if @UTC between @SSM and @FSN 
    set @StandardOffset = @StandardOffset + 1 

-- convert to DST 
set @DST = dateadd(hour,@StandardOffset,@UTC) 

-- return converted datetime 
return @DST 

END 

GO 

Cependant, cela reste me donne le même résultat que ci-dessus. 1. Que dois-je changer pour l'heure du Centre? 2. Y a-t-il un moyen de passer automatiquement à -5 pendant l'heure d'été et -6 pendant l'heure d'hiver?

EDIT:

Après avoir examiné la réponse et la reference link de # Siyual, j'ai créé la table dbo.TZCalendar et j'ai essayé de créer une fonction comme celui-ci (prend un argument et renvoie une date de lien refrence)

CREATE FUNCTION dbo.ConvertUTCToLocal 
(
    @utc DATETIME 
) 
RETURNS Datetime 
AS BEGIN 
    SELECT UTCToLocal = DATEADD(HOUR, CASE 

    -- within Daylight Savings Time 
    WHEN @utc >= UTC_DST_Start AND @utc < UTC_DST_End 
    THEN -5 

    -- within Standard Time 
    ELSE -6 END, @utc) 

FROM dbo.TZCalendar 
WHERE CONVERT(DATE,@utc) >= [Year] 
    AND CONVERT(DATE,@utc) < DATEADD(YEAR, 1, [Year]) 
END 
GO 

Cela ne fonctionne pas. La logique semble juste pour moi, mais, j'ai juste besoin d'une fonction sans SCHEMABINDING (ce qui est fait dans le lien de référence). Comment puis je faire ça?

+0

double possible de [Sql Server Spécifiez le temps dans un autre fuseau horaire] (https://stackoverflow.com/questions/30919935/sql-server-specify-time-in-another-timezone) – Siyual

+0

@Siyual merci pour le lien. J'ai une question, dans mon article, comme je l'ai mentionné (formulaire # Ron's answer), y a-t-il un moyen de faire automatiquement les économies de l'heure d'été sans avoir à entrer le décalage manuellement? –

+0

La réponse liée prend en compte DST. Vous avez juste besoin de changer les colonnes 'ET' en' CT' et de changer les offsets de '-4' et' -5' en '-5' et' -6'. – Siyual

Répondre

0

La réponse liée (Sql Server Specify time in another timezone) vous permettra d'obtenir la plupart du temps, mais pour répondre au reste de votre question, vous devrez apporter quelques modifications.

Tout d'abord, je voudrais créer un calendrier DST, depuis la DST dates de début et de fin sont quelque chose que nous pouvons calculer:

CREATE TABLE dbo.TZCalendar 
(
    Year   Int PRIMARY KEY, 
    UTC_DST_Start SMALLDATETIME NOT NULL, 
    UTC_DST_End SMALLDATETIME NOT NULL 
); 

SET DATEFIRST 7; 

;WITH cte(d,p) AS 
(
    -- all the years from 2000 through 50 years after the current year: 
    SELECT TOP (YEAR(GETDATE())-2000+51) DATEADD(YEAR,number,'20000101'), 
    CASE WHEN number < 7 THEN 1 ELSE 0 END -- year < 2007 = 1, else 0 
    FROM [master].dbo.spt_values WHERE [type] = N'P' ORDER BY number 
) 
INSERT dbo.TZCalendar([Year],UTC_DST_Start,UTC_DST_End) 
SELECT Year(d), 
-- First Sunday in April (< 2007) or second Sunday in March (>= 2007): 
DATEADD(HOUR, 7, DATEADD(DAY,(7-DATEPART(WEEKDAY,DATEADD(MONTH,2+p,d))+1)%7 
    +(7*ABS(p-1)),DATEADD(MONTH,2+p,d))), 
-- Last Sunday in October (< 2007) or first Sunday in November (>= 2007): 
DATEADD(HOUR, 6, DATEADD(DAY,(7-DATEPART(WEEKDAY,DATEADD(MONTH,10,d))+1)%7 
    -(7*p),DATEADD(MONTH,10,d))) 
FROM cte 
ORDER BY d; 

Cela va générer les temps l'heure d'été de l'année 2000-2067 (ce qui peut être élargi en fonction de vos besoins).

Ensuite, je créerais une fonction de prendre une DATE dans UTC et retourner la valeur dans les deux CST ou CDT, en fonction du moment de l'année.

Create Function dbo.fnConvertUTCToCT(@UTC DateTime) 
Returns DateTime 
As Begin 
    Declare @Offset Int = 0 

    Select @Offset = Case When @UTC Between UTC_DST_Start And UTC_DST_End Then -5 Else -6 End 
    From dbo.TZCalendar 
    Where Year = Year(@UTC) 

    Set @UTC = DateAdd(Hour, @Offset, @UTC) 

    Return @UTC 
End 

Ensuite, vous pouvez simplement appeler cette fonction avec un moment précis et obtenir la traduction CST ou CDT retourné:

Select dbo.fnConvertUTCToCT(GetUTCDate()) 

2017-09-27 12:24:26.377

+0

merci et ça marche bien maintenant. Une question rapide, au lieu de montrer le format de 24 heures, est-il un moyen pour le format de 12 heures. J'ai cherché, pas de chance! Ce n'est pas important, je me demandais juste. Merci encore! –

+1

@Jesse Puisque vous utilisez SQL Server 2012+, vous pouvez utiliser ['FORMAT()'] (https://docs.microsoft.com/en-us/sql/t-sql/functions/format-transact-sql). Un exemple serait: 'Sélectionnez Format (GetDate(), N'yyyy-MM-jj hh: mm: ss tt ')'. – Siyual

+1

c'est vrai, je ne pouvais pas y penser! Impressionnant! Continuez à bercer :) –

2

Si vous utilisez SQL Server 2016+ (ou Azure Database SQL) ceci est construit en:

SELECT YourInputDatetimeInUTC AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time' 

Le premier affirme votre contribution est UTC, le second, il se transforme en États-Unis Heure centrale, y compris l'heure d'été, le cas échéant (en utilisant un identifiant de fuseau horaire Windows).

Cependant, puisque vous avez dit SQL 2012, je recommande mon projet SQL Server Time Zone Support, lorsque cela est une opération simple et utilise des identifiants IANA:

SELECT Tzdb.UtcToLocal(YourInputDatetimeInUTC, 'America/Chicago') 
+0

Merci! Installé SQL Server 2016 et créé une table temporaire avec un temps différent pour voir la différence pour essayer votre premier ensemble de code et fonctionne parfaitement. Bon travail! Je voudrais pouvoir accepter les deux comme réponse (OP est en 2012) –