microsoft descargar caracteristicas sql sql-server

caracteristicas - sql server descargar



Convierta la columna de fecha y hora de UTC a la hora local en la instrucción de selección (16)

Aquí hay una versión que cuenta con ahorros de luz diurna, compensación UTC, y no está bloqueada en un año en particular.

--------------------------------------------------------------------------------------------------- --Name: udfToLocalTime.sql --Purpose: To convert UTC to local US time accounting for DST --Author: Patrick Slesicki --Date: 3/25/2014 --Notes: Works on SQL Server 2008R2 and later, maybe SQL Server 2008 as well. -- Good only for US States observing the Energy Policy Act of 2005. -- Function doesn''t apply for years prior to 2007. -- Function assumes that the 1st day of the week is Sunday. --Tests: -- SELECT dbo.udfToLocalTime(''2014-03-09 9:00'', DEFAULT) -- SELECT dbo.udfToLocalTime(''2014-03-09 10:00'', DEFAULT) -- SELECT dbo.udfToLocalTime(''2014-11-02 8:00'', DEFAULT) -- SELECT dbo.udfToLocalTime(''2014-11-02 9:00'', DEFAULT) --------------------------------------------------------------------------------------------------- ALTER FUNCTION udfToLocalTime ( @UtcDateTime AS DATETIME ,@UtcOffset AS INT = -8 --PST ) RETURNS DATETIME AS BEGIN DECLARE @PstDateTime AS DATETIME ,@Year AS CHAR(4) ,@DstStart AS DATETIME ,@DstEnd AS DATETIME ,@Mar1 AS DATETIME ,@Nov1 AS DATETIME ,@MarTime AS TIME ,@NovTime AS TIME ,@Mar1Day AS INT ,@Nov1Day AS INT ,@MarDiff AS INT ,@NovDiff AS INT SELECT @Year = YEAR(@UtcDateTime) ,@MarTime = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset, ''1900-01-01 02:00'')) ,@NovTime = CONVERT(TIME, DATEADD(HOUR, -@UtcOffset - 1, ''1900-01-01 02:00'')) ,@Mar1 = CONVERT(CHAR(16), @Year + ''-03-01 '' + CONVERT(CHAR(5), @MarTime), 126) ,@Nov1 = CONVERT(CHAR(16), @Year + ''-11-01 '' + CONVERT(CHAR(5), @NovTime), 126) ,@Mar1Day = DATEPART(WEEKDAY, @Mar1) ,@Nov1Day = DATEPART(WEEKDAY, @Nov1) --Get number of days between Mar 1 and DST start date IF @Mar1Day = 1 SET @MarDiff = 7 ELSE SET @MarDiff = 15 - @Mar1Day --Get number of days between Nov 1 and DST end date IF @Nov1Day = 1 SET @NovDiff = 0 ELSE SET @NovDiff = 8 - @Nov1Day --Get DST start and end dates SELECT @DstStart = DATEADD(DAY, @MarDiff, @Mar1) ,@DstEnd = DATEADD(DAY, @NovDiff, @Nov1) --Change UTC offset if @UtcDateTime is in DST Range IF @UtcDateTime >= @DstStart AND @UtcDateTime < @DstEnd SET @UtcOffset = @UtcOffset + 1 --Get Conversion SET @PstDateTime = DATEADD(HOUR, @UtcOffset, @UtcDateTime) RETURN @PstDateTime END GO

Estoy haciendo algunas consultas de selección de SQL y me gustaría convertir mi columna de fecha y hora de UTC en hora local para que se muestre como hora local en los resultados de mi consulta. Tenga en cuenta que NO estoy buscando hacer esta conversión a través de código, sino más bien cuando estoy haciendo consultas SQL manuales y aleatorias en contra de mis bases de datos.


Aquí hay uno más simple que toma en cuenta

CREATE FUNCTION [dbo].[UtcToLocal] ( @p_utcDatetime DATETIME ) RETURNS DATETIME AS BEGIN RETURN DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), @p_utcDatetime), GETDATE()) END


Como advertencia, si va a utilizar lo siguiente (tenga en cuenta los milisegundos en lugar de minutos):

SELECT DATEADD(ms, DATEDIFF(ms, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) AS ColumnInLocalTime FROM MyTable

Tenga en cuenta que la parte DATEDIFF no siempre devolverá el mismo número. Entonces no lo use para comparar DateTimes a milisegundos.


Descubrí que esta función es más rápida que otras soluciones que usan una tabla o bucles separados. Es solo una declaración de caso básica. Dado que todos los meses entre abril y octubre tienen una compensación de -4 horas (hora del este), solo necesitamos agregar algunas líneas más para los días marginales. De lo contrario, el desplazamiento es -5 horas.

Esto es específico para una conversión de UTC a hora del este, pero se pueden agregar funciones de zona horaria adicionales según sea necesario.

USE [YourDatabaseName] GO /****** Object: UserDefinedFunction [dbo].[ConvertUTCtoEastern] Script Date: 11/2/2016 5:21:52 PM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE FUNCTION [dbo].[ConvertUTCtoEastern] ( @dtStartDate DATETIME ) RETURNS DATETIME AS BEGIN DECLARE @Working DATETIME DECLARE @Returned DATETIME SET @Working = @dtStartDate SET @Working = case when month(@Working) between 4 and 10 then dateadd(HH,-4,@Working) when @Working between ''2017-03-12'' and ''2017-11-05'' then dateadd(HH,-4,@Working) when @Working between ''2016-03-13'' and ''2016-11-06'' then dateadd(HH,-4,@Working) when @Working between ''2015-03-08'' and ''2015-11-01'' then dateadd(HH,-4,@Working) when @Working between ''2014-03-09'' and ''2014-11-02'' then dateadd(HH,-4,@Working) when @Working between ''2013-03-10'' and ''2013-11-03'' then dateadd(HH,-4,@Working) when @Working between ''2012-03-11'' and ''2012-11-04'' then dateadd(HH,-4,@Working) else dateadd(HH,-5,@Working) end SET @Returned = @Working RETURN @Returned END GO


Encontré que el modo de función inactivo es demasiado lento cuando hay una gran cantidad de datos. Así que lo hice uniéndome a una función de tabla que permitiría un cálculo de la diferencia horaria. Básicamente se trata de segmentos de fecha y hora con el desplazamiento de la hora. Un año sería 4 filas. Entonces la función de tabla

dbo.fn_getTimeZoneOffsets(''3/1/2007 7:00am'', ''11/5/2007 9:00am'', ''EPT'')

Devolvería esta tabla:

startTime endTime offset isHr2 3/1/07 7:00 3/11/07 6:59 -5 0 3/11/07 7:00 11/4/07 6:59 -4 0 11/4/07 7:00 11/4/07 7:59 -5 1 11/4/07 8:00 11/5/07 9:00 -5 0

No cuenta para el horario de verano. Una muestra de cómo se usa está debajo y la publicación completa del blog está here .

select mt.startTime as startUTC, dateadd(hh, tzStart.offset, mt.startTime) as startLocal, tzStart.isHr2 from MyTable mt inner join dbo.fn_getTimeZoneOffsets(@startViewUTC, @endViewUTC, @timeZone) tzStart on mt.startTime between tzStart.startTime and tzStart.endTime


Esto debería poder obtener el tiempo del servidor con DST

declare @dt datetime set @dt = getutcdate() -- GMT equivalent

sysdatetimeoffset tiene DST en cuenta

select [InputTime] = @dt , [LocalTime2] = dateadd(mi, datediff(mi, sysdatetimeoffset(),getdate()), @dt)


La respuesta de Ron contiene un error. Utiliza las 2:00 a.m. hora local donde se requiere el equivalente UTC. No tengo suficientes puntos de reputación para comentar la respuesta de Ron, por lo que aparece una versión corregida a continuación:

-- ============================================= -- Author: Ron Smith -- Create date: 2013-10-23 -- Description: Converts UTC to DST -- based on passed Standard offset -- ============================================= 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,2 - @StandardOffset,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM)) set @FSN = datename(year,@UTC) + ''1107'' set @FSN = dateadd(second,-1,dateadd(hour,2 - (@StandardOffset + 1),dateadd(day,datepart(dw,@FSN)*-1+1,@FSN))) -- 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


Ninguno de estos funcionó para mí, pero esto a continuación funcionó al 100%. Espero que esto ayude a otros a tratar de convertirlo como yo.

CREATE FUNCTION [dbo].[fn_UTC_to_EST] ( @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 = DATEADD(dd,7 + (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))+''02:00:00'' set @FSN = DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0)) +''02:00:00'' -- 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


No encontré ninguno de estos ejemplos útil para obtener una fecha y hora almacenada como UTC en una fecha y hora en una zona horaria específica (NO la zona horaria del servidor porque las bases de datos SQL de Azure se ejecutan como UTC). Así es como lo manejé. No es elegante, pero es simple y te da la respuesta correcta sin mantener otras tablas:

select CONVERT(datetime, SWITCHOFFSET(dateTimeField, DATEPART(TZOFFSET, dateTimeField AT TIME ZONE ''Eastern Standard Time'')))


No hay una manera simple de hacer esto de una manera correcta Y genérica.

En primer lugar, debe entenderse que la compensación depende de la fecha en cuestión, la zona horaria y el horario de verano. GetDate()-GetUTCDate solo le da el desplazamiento hoy en el TZ del servidor, que no es relevante.

Solo he visto dos soluciones de trabajo y busco mucho.

1) Una función SQL personalizada con un par de tablas de datos base, tales como Zonas horarias y reglas DST por TZ. Trabajando pero no muy elegante. No puedo publicarlo ya que no soy el propietario del código.

EDITAR: Aquí hay un ejemplo de este método https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2) Agregue un ensamblado .net al db, .Net puede hacer esto muy fácilmente. Esto funciona muy bien, pero la desventaja es que debe configurar varios parámetros en el nivel del servidor y la configuración se rompe fácilmente, por ejemplo, si restaura la base de datos. Utilizo este método pero no puedo publicarlo ya que no poseo el código.


Primera función: configurada para la zona horaria italiana (+1, +2), cambie las fechas: último domingo de marzo y octubre, devuelva la diferencia entre la zona horaria actual y la fecha y hora como parámetro.

Returns: current timezone < parameter timezone ==> +1 current timezone > parameter timezone ==> -1 else 0

El código es:

CREATE FUNCTION [dbo].[UF_ADJUST_OFFSET] ( @dt_utc datetime2(7) ) RETURNS INT AS BEGIN declare @month int, @year int, @current_offset int, @offset_since int, @offset int, @yearmonth varchar(8), @changeoffsetdate datetime2(7) declare @lastweek table(giorno datetime2(7)) select @current_offset = DATEDIFF(hh, GETUTCDATE(), GETDATE()) select @month = datepart(month, @dt_utc) if @month < 3 or @month > 10 Begin Set @offset_since = 1 Goto JMP End if @month > 3 and @month < 10 Begin Set @offset_since = 2 Goto JMP End --If i''m here is march or october select @year = datepart(yyyy, @dt_utc) if @month = 3 Begin Set @yearmonth = cast(@year as varchar) + ''-03-'' Insert Into @lastweek Values(@yearmonth + ''31 03:00:00.000000''),(@yearmonth + ''30 03:00:00.000000''),(@yearmonth + ''29 03:00:00.000000''),(@yearmonth + ''28 03:00:00.000000''), (@yearmonth + ''27 03:00:00.000000''),(@yearmonth + ''26 03:00:00.000000''),(@yearmonth + ''25 03:00:00.000000'') --Last week of march Select @changeoffsetdate = giorno From @lastweek Where datepart(weekday, giorno) = 1 if @dt_utc < @changeoffsetdate Begin Set @offset_since = 1 End Else Begin Set @offset_since = 2 End End if @month = 10 Begin Set @yearmonth = cast(@year as varchar) + ''-10-'' Insert Into @lastweek Values(@yearmonth + ''31 03:00:00.000000''),(@yearmonth + ''30 03:00:00.000000''),(@yearmonth + ''29 03:00:00.000000''),(@yearmonth + ''28 03:00:00.000000''), (@yearmonth + ''27 03:00:00.000000''),(@yearmonth + ''26 03:00:00.000000''),(@yearmonth + ''25 03:00:00.000000'') --Last week of october Select @changeoffsetdate = giorno From @lastweek Where datepart(weekday, giorno) = 1 if @dt_utc > @changeoffsetdate Begin Set @offset_since = 1 End Else Begin Set @offset_since = 2 End End JMP: if @current_offset < @offset_since Begin Set @offset = 1 End Else if @current_offset > @offset_since Set @offset = -1 Else Set @offset = 0 Return @offset END

Entonces la función que convierte la fecha

CREATE FUNCTION [dbo].[UF_CONVERT] ( @dt_utc datetime2(7) ) RETURNS datetime AS BEGIN declare @offset int Select @offset = dbo.UF_ADJUST_OFFSET(@dt_utc) if @dt_utc >= ''9999-12-31 22:59:59.9999999'' set @dt_utc = ''9999-12-31 23:59:59.9999999'' Else set @dt_utc = (SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), @dt_utc) ) if @offset <> 0 Set @dt_utc = dateadd(hh, @offset, @dt_utc) RETURN @dt_utc END


Puede hacerlo de la siguiente manera en SQL Server 2008 o superior:

SELECT CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, MyTable.UtcColumn), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS ColumnInLocalTime FROM MyTable

También puede hacer lo menos detallado:

SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), MyTable.UtcColumn) AS ColumnInLocalTime FROM MyTable

Hagas lo que hagas, no lo uses - para restar fechas, porque la operación no es atómica y ocasionalmente obtendrás resultados indeterminados debido a las condiciones de carrera entre el sistema datetime y el horario local verificado en diferentes momentos (es decir, no atómicamente) )

Tenga en cuenta que esta respuesta no tiene en cuenta el horario de verano. Si desea incluir un ajuste de horario de verano, consulte también la siguiente pregunta de SO:

Cómo crear la función de inicio y finalización del horario de verano en SQL Server


Si habilitar CLR en su base de datos es una opción así como también usar la zona horaria del servidor sql, se puede escribir en .Net con bastante facilidad.

public partial class UserDefinedFunctions { [Microsoft.SqlServer.Server.SqlFunction] public static SqlDateTime fn_GetLocalFromUTC(SqlDateTime UTC) { if (UTC.IsNull) return UTC; return new SqlDateTime(UTC.Value.ToLocalTime()); } }

Un valor de fecha y hora UTC entra y sale el valor de fecha y hora local relativo al servidor. Los valores nulos devuelven nulo.


Si necesita una conversión que no sea la ubicación de su servidor, aquí hay una función que le permite pasar un desplazamiento estándar y cuentas para los Horarios de verano de los Estados Unidos:

-- ============================================= -- Author: Ron Smith -- Create date: 2013-10-23 -- Description: Converts UTC to DST -- based on passed Standard offset -- ============================================= 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,2,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM)) set @FSN = datename(year,@UTC) + ''1107'' set @FSN = dateadd(second,-1,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN))) -- 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


Usando nuevas oportunidades de SQL Server 2016:

CREATE FUNCTION ToLocalTime(@dtUtc datetime, @timezoneId nvarchar(256)) RETURNS datetime AS BEGIN return @dtUtc AT TIME ZONE ''UTC'' AT TIME ZONE @timezoneId /* -- second way, faster return SWITCHOFFSET(@dtUtc , DATENAME(tz, @dtUtc AT TIME ZONE @timezoneId)) */ /* -- third way declare @dtLocal datetimeoffset set @dtLocal = @dtUtc AT TIME ZONE @timezoneId return dateadd(minute, DATEPART (TZoffset, @dtLocal), @dtUtc) */ END GO

Pero el procedimiento clr funciona 5 veces más rápido: ''- (

Preste atención a que Offset para una TimeZone puede cambiar a invierno o verano. Por ejemplo

select cast(''2017-02-08 09:00:00.000'' as datetime) AT TIME ZONE ''Eastern Standard Time'' select cast(''2017-08-08 09:00:00.000'' as datetime) AT TIME ZONE ''Eastern Standard Time''

resultados:

2017-02-08 09:00:00.000 -05:00 2017-08-08 09:00:00.000 -04:00

No puedes simplemente agregar compensación constante.


declare @mydate2 datetime set @mydate2=Getdate() select @mydate2 as mydate, dateadd(minute, datediff(minute,getdate(),@mydate2),getutcdate())