Estamos tratando con una aplicación que necesita manejar datos de hora global de diferentes zonas horarias y configuraciones de horario de verano. La idea es almacenar todo en formato UTC internamente y solo convertir de un lado a otro para las interfaces de usuario localizadas. ¿Ofrece SQL Server algún mecanismo para tratar las traducciones en un momento, un país y una zona horaria?
Este debe ser un problema común, por lo que me sorprende que Google no muestre nada utilizable.
¿Algún consejo?
sql-server
tsql
sql-server-2008
timezone
utc
BuschnicK
fuente
fuente
Respuestas:
Pasaron 7 años y ... de
hecho, existe esta nueva característica de SQL Server 2016 que hace exactamente lo que necesita.
Se llama AT TIME ZONE y convierte la fecha en una zona horaria especificada considerando los cambios de DST (horario de verano).
Más información aquí: https://msdn.microsoft.com/en-us/library/mt612795.aspx
fuente
Esto funciona para fechas que actualmente tienen el mismo desplazamiento UTC que el host de SQL Server; no tiene en cuenta los cambios de horario de verano. Reemplace
YOUR_DATE
con la fecha local para convertir.SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);
fuente
Si bien algunas de estas respuestas lo llevarán al estadio de béisbol, no puede hacer lo que está tratando de hacer con fechas arbitrarias para SqlServer 2005 y anteriores debido al horario de verano. Usar la diferencia entre el UTC actual y el local actual me dará el desplazamiento tal como existe hoy. No he encontrado una manera de determinar cuál habría sido la compensación para la fecha en cuestión.
Dicho esto, sé que SqlServer 2008 proporciona algunas funciones de fecha nuevas que pueden abordar ese problema, pero las personas que usan una versión anterior deben conocer las limitaciones.
Nuestro enfoque es mantener UTC y realizar la conversión en el lado del cliente, donde tenemos más control sobre la precisión de la conversión.
fuente
Para SQL Server 2016 y versiones posteriores, y Azure SQL Database, use la
AT TIME ZONE
instrucción integrada .Para las ediciones anteriores de SQL Server, puede usar mi proyecto de soporte de zona horaria de SQL Server para convertir entre zonas horarias estándar de IANA, como se enumeran aquí .
UTC a Local es así:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')
Local a UTC es así:
SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1)
Las opciones numéricas son un indicador para controlar el comportamiento cuando los valores de la hora local se ven afectados por el horario de verano. Estos se describen en detalle en la documentación del proyecto.
fuente
SQL Server 2008 tiene un tipo llamado
datetimeoffset
. Es realmente útil para este tipo de cosas.http://msdn.microsoft.com/en-us/library/bb630289.aspx
Luego, puede usar la función
SWITCHOFFSET
para moverla de una zona horaria a otra, pero manteniendo el mismo valor UTC.http://msdn.microsoft.com/en-us/library/bb677244.aspx
Robar
fuente
Aquí está el código para convertir una zona
DateTime
en otra zonaDateTime
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
Nota :
AT TIME ZONE
funciona solo en SQL Server 2016+ y la ventaja es que considera automáticamente la luz del día cuando se convierte a una zona horaria en particularfuente
AT TIME ZONE
llamadas (¿frases?) Juntas. Simplemente elegante. Dije anteriormente que stackoverflow.com/a/44579178/112764 satisfacía mis necesidades, pero esto es aún mejor. Felicitaciones importantes.DECLARE @UTCDateTime DATETIME = GETUTCDATE();
DECLARE @ConvertedZoneDateTime DATETIME;
-- 'UTC' to 'India Standard Time' to 'Eastern Standard Time' DATETIME
SET @ConvertedZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time' AT TIME ZONE 'Eastern Standard Time'
SELECT @UTCDateTime AS UTCDATE,@ConvertedZoneDateTime AS EasternStandardTime
Sí, puede encadenar variasAT TIME ZONE
llamadas, pero From y To es suficiente para cualquier conversión y la mayoría de las que necesitábamosTiendo a inclinarme hacia el uso de DateTimeOffset para todo el almacenamiento de fecha y hora que no está relacionado con un evento local (es decir, reunión / fiesta, etc., de 12 p.m. a 3 p.m. en el museo).
Para obtener el DTO actual como 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]
NOTA: Siempre usaré UTC al enviar por cable ... JS del lado del cliente puede llegar fácilmente a / desde UTC local. Ver:
new Date().toJSON()
...El siguiente JS manejará el análisis de una fecha UTC / GMT en formato ISO8601 a una fecha y hora local.
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; }; }
fuente
Sí, hasta cierto punto como se detalla aquí .
El enfoque que utilicé (antes de 2008) es realizar la conversión en la lógica empresarial de .NET antes de insertarla en la base de datos.
fuente
Puede usar la función GETUTCDATE () para obtener la fecha y hora UTC Probablemente pueda seleccionar la diferencia entre GETUTCDATE () y GETDATE () y usar esta diferencia para ajustar sus fechas a UTC
Pero estoy de acuerdo con el mensaje anterior, que es mucho más fácil controlar la fecha y hora correcta en la capa empresarial (en .NET, por ejemplo).
fuente
Uso de muestra:
SELECT Getdate=GETDATE() ,SysDateTimeOffset=SYSDATETIMEOFFSET() ,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0) ,GetutcDate=GETUTCDATE() GO
Devoluciones:
fuente