Al fin luego de mucho trabajar ya hallamos el resultado de este enigma que tantos usuarios de nuestro espacio presentan. Si tienes alguna información que aportar puedes dejar tu comentario.
Solución:
La primera línea de su código contiene la falla:
SELECT GETUTCDATE() AT TIME ZONE 'GMT Standard Time'
GETUTCDATE()
devuelve un datetime
, que no tiene información de compensación de zona horaria. Por lo tanto, como se describe en la documentación de MSDN:
Si fecha de entrada se proporciona sin información de compensación, la función aplica la compensación de la zona horaria asumiendo que fecha de entrada el valor se proporciona en la zona horaria de destino.
Entonces, aunque recuperó la hora UTC, afirmó erróneamente que el valor estaba en la hora de Londres (que es UTC+1 para el horario de verano en esta fecha).
La forma más fácil de manejar esto es obtener la hora UTC como un datetimeoffset
para empezar.
SELECT SYSDATETIMEOFFSET() AT TIME ZONE 'GMT Standard Time'
Esto invoca la conversión funcionalidad de AT TIME ZONE
que en los documentos dice:
Si fecha de entrada se proporciona como un desplazamiento de fecha y hora valor, entonces
AT TIME ZONE
la cláusula lo convierte en la zona horaria de destino utilizando reglas de conversión de zona horaria.
Considere que si sus datos realmente provienen de un datetime
campo en algún lugar, es posible que necesite usar ambos partes de la funcionalidad, así:
SELECT mydatetimefield AT TIME ZONE 'UTC' AT TIME ZONE 'GMT Standard Time'
La primera llamada a AT TIME ZONE
afirma que el valor está en UTC, dando un datetimeoffset
a la segunda llamada, que la convierte a la hora de Londres.
La salida de cualquiera de estos es un datetimeoffset
que puedes emitir o convertir en un datetime
o datetime2
exactamente como mostraste en tu pregunta original. (No use switchoffset
para esto.)
Además, el identificador de zona horaria de Windows para Londres siempre es "GMT Standard Time"
. Incluye tanto el meridiano de Greenwich como el horario de verano británico, con las transiciones adecuadas entre ellos. No intente cambiarlo a "GMT Daylight Time"
– ese identificador no existe. Esto también se trata en la wiki de etiquetas de zona horaria, en la sección sobre zonas horarias de Windows.
Como no pude encontrar esto en ningún otro lugar, pensé en compartirlo. Puede obtener la compensación en minutos usando la parte de fecha (tz) con AT TIME ZONE.
datepart(tz,UTC_Date AT TIME ZONE 'Central Standard Time')
select dateadd(MINUTE,datepart(tz,cast('2018-07-02 17:54:41.537' as datetime) AT Time Zone 'Central Standard Time'),'2018-07-02 17:54:41.537') as CentralTime
devoluciones
CentralTime
2018-07-02 12:54:41.537