2011-05-19 37 views
10

Tengo un proceso de inserción que pasa en GETDATE() como uno de los valores porque cada inserción también se almacena cuando se insertó. Está alojado en SQL Azure, que usa GMT.SQL Server 2008 - ¿Cómo convertir la fecha y hora de GMT (UTC) a hora local?

Ahora, cuando recibo mensajes, tengo la fecha GMT almacenada para cada uno de ellos en sus columnas de marca de tiempo, ¿cómo puedo convertir esto al datetime local donde quiera que estés cuando estás accediendo a mi página?

Gracias.

+2

cambió la hora del servidor? ¿Puedes revisar? –

+0

Umm, se ejecuta en SQL Azure. ¿Cómo verificaría? – slandau

+0

¿no puedes simplemente hacer un "SELECCIONAR GETDATE() IR" y ver si coincide con lo que estás esperando? – Mat

Respuesta

10

Se podría hacer algo como esto:

declare @InputUtcDateTime datetime2 = '2011-05-20 06:30:18' 

declare @LocalDateTime datetime2 = dateadd(minute, datepart(TZoffset, sysdatetimeoffset()), @InputUtcDateTime) 
print @LocalDateTime 

o

declare @InputUtcDateTime datetime2 = '2011-05-20 06:30:18' 

declare @LocalDateTime datetime2 = dateadd(minute, datediff(minute, sysutcdatetime(), sysdatetime()), @InputUtcDateTime) 
print @LocalDateTime 
+28

Ambos son incorrectos. Se basan en la suposición de que la compensación de la zona horaria local de hoy es la misma que la compensación para la zona horaria local en el momento indicado por la fecha UTC de entrada. Dado que la zona horaria local puede estar sujeta a DST, su desplazamiento puede ser diferente en el pasado de lo que es hoy. – wasabi

+3

@wasabi +1: tiene razón acerca de la limitación de este enfoque. Sin embargo, no estoy de acuerdo con que sea incorrecto. Depende de lo que estás tratando de lograr. –

+6

¿Está intentando recuperar el tiempo correcto para una zona horaria local, dado un tiempo de entrada arbitrario? – wasabi

1

Para MST como un ejemplo ... teniendo en cuenta cada DTM se almacena en ya GMT, que simplifica las cosas ..

SWITCHOFFSET(CONVERT(DATETIMEOFFSET, [ColumnName]), '-07:00') 

Ahora, si su fecha/hora local es distinta de GMT/UTC, es probable que desee utilizar lo siguiente ...

SWITCHOFFSET(TODATETIMEOFFSET([ColumnName], datepart(tz,sysdatetimeoffset())),'+00:00') 

Aquí está el desglose.

  • SWITCHOFFSET - convierte un valor de DateTimeOffset en una zona horaria diferente, mientras se conserva el desplazamiento.
  • TODATETIMEOFFSET - convierte un valor de DateTime a un valor DateTimeOffset en una zona horaria específica.
  • DATEPART - en este caso, la zona horaria forma parte de la hora local.
  • '+00:00' - el desplazamiento del objetivo, en el segundo ejemplo es el objetivo UTC/GMT, del local ... el ejemplo anterior es MST.

NOTA/ADVERTENCIA: No creo que esto represente el horario de verano, lo que podría ser un problema para usted. Si no es necesaria la preservación absoluta, puede agregar una columna secundaria, con la conversión aproximada y avanzar de manera segura.

Es posible que desee abstraer la lógica en una llamada a función, para tener en cuenta la preservación del horario de verano ... sin embargo, no debería ser excesivamente difícil de hacer.

0

Aquí hay una función que funciona con datos históricos. Lo escribí para el horario de verano británico, que desafortunadamente ocurre el último domingo de los meses de marzo y octubre, haciendo la lógica un poco intrincada.

Básicamente, la parte de fecha codificada 01/03 está buscando el último domingo de marzo y 01/10 está buscando el último domingo de octubre (que es cuando los relojes avanzan y vuelven). NOTA: ¡SI SU SERVIDOR ESTÁ UTILIZANDO LAS FECHAS NATIVAS DE ESTADOS UNIDOS, REVERSE LAS DOS PUNTOS DE LA FECHA HASTA EL 03/01 Y EL 10/01!

Así que le das una fecha UTC y automáticamente se resuelve si una fecha histórica es BST o GMT. No es lo mejor para usar en un gran conjunto de datos, pero es una solución.

Ejecute este script para crear la función y llámelo en línea en su selección.SQL 2008 tiene un problema con las funciones definidas por el usuario, parece que pone una línea roja debajo del código, pero aún lo ejecuta siempre que use el prefijo dbo (SELECCIONE dbo.UTCConvert (su fecha) para ejecutarlo)

CREATE FUNCTION [dbo].[UTCConvert] 
(

    @p1 datetime 
) 
RETURNS datetime 
AS 
BEGIN 

    DECLARE @Result datetime 


RETURN CASE 
WHEN 
@p1 > 
(DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,'01/03/' + CAST(DATEPART(year,@p1) as CHAR)),30))/7*7,'19000107')) 
AND 
@p1< 
(DATEADD(day,DATEDIFF(day,'19000107',DATEADD(month,DATEDIFF(MONTH,0,'01/10/' + CAST(DATEPART(year,@p1) as CHAR)),30))/7*7,'19000107')) 
THEN (DATEADD(HH, 1, @p1)) 
ELSE @p1 
END 
END 
+0

Si su servidor usa fechas nativas de los EE. UU. Porque está ubicado en los EE. UU., Lo más probable es que tenga dolores de cabeza mucho más severos. Las probabilidades son que si está viendo esta pregunta, está almacenando fechas desde al menos un lugar donde se aplican los ahorros de luz diurna. Eso significa que, como mínimo, debe preocuparse por el cambio de 2007 en las fechas de cambio. Es posible que tenga que preocuparse por múltiples zonas horarias, posiblemente Arizona y tal vez incluso la Nación Navajo. Realmente desea almacenar UTC o datetimeoffset en SQL Server y hacer su matemática de fecha en la capa de su empresa. – MattW

5

Aparte de la cuestión horario de verano, ¿por qué no simplifica con:

yourDateTime - getutcdate() + getdate() 
Cuestiones relacionadas