Convierta la columna Datetime de UTC a hora local en la instrucción select


208

Estoy haciendo algunas consultas de selección SQL y me gustaría convertir mi columna de fecha y hora 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 del código, sino más bien cuando estoy haciendo consultas SQL manuales y aleatorias en mis bases de datos.


¿Esta pregunta parece similar a tus circunstancias? stackoverflow.com/questions/3404646/…
Taryn East

Respuestas:


322

Puede hacer esto 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 puedes hacer lo menos detallado:

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

Hagas lo que hagas, no lo utilices -para restar fechas, porque la operación no es atómica, y en ocasiones obtendrás resultados indeterminados debido a que las condiciones de carrera entre la fecha y hora del sistema se verifican 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 DST, consulte también la siguiente pregunta SO:

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


38
¿Hay alguna manera de hacer que esta cuenta ahorre luz diurna?
Steve

15
No veo el nombre de una zona horaria aquí, así que esto es incorrecto. Es una muy mala idea suponer que se puede convertir a la hora local haciendo aritmética
JonnyRaa

77
@MichaelGoldshteyn si tiene una compensación de zona horaria, todavía no sabe en qué zona horaria lógica se encuentra la hora. Las zonas horarias son cosas sociales y los gobiernos pueden cambiarlas en diferentes puntos. El desplazamiento para una zona horaria puede ser diferente en diferentes puntos en el tiempo / historial (el horario de verano es común). Está compensando una hora con la compensación actual de UTC ... un punto adicional es que esto le dará a la zona horaria del servidor y no al cliente, lo que podría ser un problema adicional si está alojando en un país diferente.
JonnyRaa

44
@Niloofar La respuesta simple es que no, y no deberías. Las fechas deben guardarse siempre en UTC (preferiblemente en función del reloj del servidor de la base de datos, no del servidor web, del servidor de aplicaciones y definitivamente no del reloj del cliente). Mostrar esa fecha y hora es una función para la capa UI, y es responsable de convertir la fecha y hora en el formato que desee (incluida una zona horaria si es necesario).
Robert McKee

11
Para cualquiera que use sql azure, este enfoque no funcionará porque todas las funciones de fecha / hora devuelven UTC, por lo que comparar GETDATE () con GETUTCDATE () no le da nada con qué trabajar y su resultado es el mismo con el que comenzó.
Brian Surowiec

59

No encontré ninguno de estos ejemplos útiles 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 le da la respuesta correcta sin mantener otras tablas:

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

44
Funciona solo para 2016 y utiliza el registro del sistema. Pero una gran solución para Azure.
Dan Cundy

2
Este funciona para tiempos azules almacenados en UTC, gracias chicos
Nulo

3
Aquí hay una lista de las cadenas que puede usar para las zonas horarias: stackoverflow.com/a/7908482/631277
Matt Kemp

1
Si usa SQL 2016 y la AT TIME ZONEsintaxis, considere stackoverflow.com/a/44941536/112764 : puede encadenar varias conversiones juntas simplemente concatenando múltiples at time zone <blah>s.
NateJ

3
Esto también es un poco extraño, pero algunas pruebas muy básicas también podrían funcionar, dateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'simplemente encadenando las AT TIME ZONEdeclaraciones. (@NateJ mencionó esto arriba, ahora lo veo)
David Mohundro el

22

Si su fecha local es la hora Eastern Standard Timey desea convertir UTC a eso, en Azure SQL y SQL Server 2016 y superior, puede hacer lo siguiente:

SELECT YourUtcColumn AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS
       LocalTime
FROM   YourTable

La lista completa de nombres de zonas horarias se puede encontrar con:

SELECT * FROM sys.time_zone_info 

Y sí, las zonas horarias están mal nombradas, aunque lo es Eastern Standard Time, se tiene en cuenta el horario de verano.


2
Las zonas
horarias

21

Si necesita una conversión que no sea la ubicación de su servidor, aquí hay una función que le permite pasar una compensación estándar y cuentas para el horario 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

2
Ron Smith Sé que esta es una publicación antigua, pero tenía curiosidad por saber qué representan los '0314' y '1107' codificados para obtener el rango DST. Parece que son días codificados que cambian debido a DTS. ¿Por qué codificarías esto cuando debería ser una fecha calculada porque los días cambian según el lugar del calendario en el que cae el segundo domingo de marzo y el primer domingo de noviembre? Los días codificados harían este código fundamentalmente defectuoso.
Mike

2
Buena pregunta :) Esas son las fechas máximas donde pueden ocurrir el segundo domingo de marzo y el primer domingo de noviembre. Las siguientes líneas establecen las variables a la fecha real.
Ron Smith

8

Uso de 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: '- (

Tenga en cuenta que Offset for one TimeZone puede cambiar a horario de 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 puede simplemente agregar desplazamiento constante.


5

Si habilitar CLR en su base de datos es una opción además de 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());
    }
}

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


5

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

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

Solo he visto dos soluciones de trabajo y he buscado mucho.

1) Una función SQL personalizada con un par de tablas de datos base, como zonas horarias y reglas DST por TZ. Trabajando pero no muy elegante. No puedo publicarlo porque no soy dueño del código.

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

2) Agregue un ensamblado .net a la base de datos, .Net puede hacer esto muy fácilmente. Esto funciona muy bien, pero la desventaja es que necesita 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. Uso este método pero no puedo publicarlo ya que no soy dueño del código.


4

Ninguno de estos funcionó para mí, pero esto a continuación funcionó al 100%. Espero que esto pueda ayudar a otros que intentan 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

1
Esta debería ser la respuesta aceptada. Lo único que cambiaría es el nombre, ya que implica que es a la hora EST, cuando realmente es a la hora local y el StandardOffset se pasa como un parámetro.
Greg Gum

De acuerdo, la mejor respuesta ... pero en lugar de tener que pasar el desplazamiento como parámetro, agregué esto dentro del cuerpo de la función:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Tom Warfield

Continuando con mi sugerencia anterior: si calcula @StandardOffset, entonces no necesita hacer la corrección DST.
Tom Warfield

3

Aquí hay una versión que representa el horario de verano, la compensación UTC y no está bloqueado 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

3

Encontré que la función de una función fuera demasiado lenta cuando hay muchos datos. Entonces 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ían 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

Cuenta para el horario de verano. A continuación se muestra una muestra de cómo se utiliza y la publicación completa del blog está aquí .

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

No parece considerar el horario de verano de manera correcta. No estoy seguro si asume que solo existe EE. UU. Y que las reglas del horario de verano nunca cambian.
vikjon0

@ vikjon0 sí, el proyecto para el que construí esto solo tenía zonas horarias de EE. UU.
JBrooks

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

1

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

-- =============================================
-- 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

Es una característica, no un error :) La mayoría de los Estados Unidos comienza el horario de verano a las 2:00 am en.wikipedia.org/wiki/Daylight_saving_time
Ron Smith

@RonSmith Sí, a las 2:00 am hora local, que tenemos que convertir a UTC para detectar si la hora UTC dada está en el rango de horario de verano.
jlspublic

1

La marca de tiempo de UNIX es simplemente el número de segundos entre una fecha particular y la época de Unix,

SELECT DATEDIFF (SEGUNDO, {d '1970-01-01'}, GETDATE ()) // Esto devolverá la marca de tiempo UNIX en el servidor SQL

puede crear una función para la hora local de fecha a la conversión UTC de Unix utilizando la función de compensación de país a la marca de tiempo de Unix en el servidor SQL


1

Es sencillo. Pruebe esto para Azure SQL Server:

SELECT YourDateTimeColumn AT TIME ZONE 'Eastern Standard Time' FROM YourTable

Para el servidor SQL local:

SELECT CONVERT(datetime2, SWITCHOFFSET(CONVERT(datetimeoffset, gETDATE()), DATENAME(TzOffset, gETDATE() AT TIME ZONE 'Eastern Standard Time'))) FROM YourTable

1
¿Qué sucede con esto durante el horario de verano (dado que la zona horaria dice específicamente "Hora estándar del este")?
Mark

1

Para los @@Versionusuarios de Azure SQL y > = SQL Server 2016, a continuación se muestra una función simple AT TIME ZONE.

CREATE FUNCTION [dbo].[Global_Convert_UTCTimeTo_LocalTime]
(
   @LocalTimeZone        VARCHAR(50),
   @UTCDateTime          DATETIME
)
RETURNS DATETIME
AS
BEGIN
   DECLARE @ConvertedDateTime DATETIME;

   SELECT @ConvertedDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE @LocalTimeZone
   RETURN @ConvertedDateTime

END
GO

Para conocer los tipos de valores que @LocalTimeZonepuede tomar, vaya a este enlace o vaya aKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones


0

Como advertencia, si va a utilizar lo siguiente (tenga en cuenta los milisegundos en lugar de los 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. Así que no lo use para comparar DateTimes a milisegundos.


0

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 un desplazamiento de -4 horas (hora del este) solo necesitamos agregar algunas líneas de casos más para los días marginales. De lo contrario, el desplazamiento es de -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

0

Esto debería ser capaz de obtener la hora del servidor con DST

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

sysdatetimeoffset tiene en cuenta el horario de verano

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

0

Primera función: configurada para la zona horaria italiana (+1, +2), fechas de cambio: último domingo de marzo y octubre, devuelve 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 codigo 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

0

- Obtener hora estándar india de utc

CREATE FUNCTION dbo.getISTTime
(
@UTCDate datetime
)
RETURNS datetime
AS
BEGIN

    RETURN dateadd(minute,330,@UTCDate)

END
GO

0

Esto se puede hacer sin una función. El código a continuación convertirá una hora UTC a la hora de la montaña que representa el horario de verano. Ajuste todos los números -6 y -7 a su zona horaria en consecuencia (es decir, para EST se ajustaría a -4 y -5 respectivamente)

--Adjust a UTC value, in the example the UTC field is identified as UTC.Field, to account for daylight savings time when converting out of UTC to Mountain time.
CASE
    --When it's between March and November, it is summer time which is -6 from UTC
    WHEN MONTH ( UTC.Field ) > 3 AND MONTH ( UTC.Field ) < 11 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    --When its March and the day is greater than the 14, you know it's summer (-6)
    WHEN MONTH ( UTC.Field ) = 3
        AND DATEPART ( DAY , UTC.Field ) >= 14 
        THEN
            --However, if UTC is before 9am on that Sunday, then it's before 2am Mountain which means it's still Winter daylight time.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 2am mountain time so it's winter, -7 hours for Winter daylight time
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise -6 because it'll be after 2am making it Summer daylight time
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    WHEN MONTH ( UTC.Field ) = 3
        AND ( DATEPART ( WEEKDAY , UTC.Field ) + 7 ) <= DATEPART ( day , UTC.Field ) 
        THEN 
            --According to the date, it's moved onto Summer daylight, but we need to account for the hours leading up to 2am if it's Sunday
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '9:00'
                    --Before 9am UTC is before 2am Mountain so it's winter Daylight, -7 hours
                    THEN DATEADD ( HOUR , -7 , UTC.Field )
                --Otherwise, it's summer daylight, -6 hours
                ELSE DATEADD ( HOUR , -6 , UTC.Field )
            END
    --When it's November and the weekday is greater than the calendar date, it's still Summer so -6 from the time
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) > DATEPART ( DAY , UTC.Field ) 
        THEN DATEADD ( HOUR , -6 , UTC.Field )
    WHEN MONTH ( UTC.Field ) = 11
        AND DATEPART ( WEEKDAY , UTC.Field ) <= DATEPART ( DAY , UTC.Field ) 
            --If the weekday is less than or equal to the calendar day it's Winter daylight but we need to account for the hours leading up to 2am.
            CASE 
                WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1 
                    AND UTC.Field < '8:00'
                    --If it's before 8am UTC and it's Sunday in the logic outlined, then it's still Summer daylight, -6 hours
                    THEN DATEADD ( HOUR , -6 , UTC.Field )
                --Otherwise, adjust for Winter daylight at -7
                ELSE DATEADD ( HOUR , -7 , UTC.Field )
            END
    --If the date doesn't fall into any of the above logic, it's Winter daylight, -7
    ELSE
        DATEADD ( HOUR , -7 , UTC.Field )
END

0

Tienes que formatear la cadena y convertirla a la hora correcta. En este caso necesitaba tiempo zulú.

Declare @Date datetime;
Declare @DateString varchar(50);
set @Date = GETDATE(); 
declare @ZuluTime datetime;

Declare @DateFrom varchar (50);
Declare @DateTo varchar (50);
set @ZuluTime = DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), @Date);
set @DateString =  FORMAT(@ZuluTime, 'yyyy-MM-ddThh:mm:ssZ', 'en-US' )  
select @DateString;

0

La mejor manera para Oracle:

Con fecha y hora codificadas:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(TO_DATE('2018-10-27 21:00', 'YYYY-MM-DD HH24:MI') AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM DUAL

Result: 2018-10-28 00:00

Con nombres de columna y tabla:

SELECT TO_CHAR(CAST((FROM_TZ(CAST(COLUMN_NAME AS TIMESTAMP), 'UTC') AT  TIME ZONE 'EET') AS DATE), 'YYYY-MM-DD HH24:MI') UTC_TO_EET FROM TABLE_NAME

0

Tengo un código para realizar las horas UTC a Local y Local a UTC que permite la conversión usando un código como este

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @utcDT DATETIME=GetUTCDate()
DECLARE @userDT DATETIME=[dbo].[funcUTCtoLocal](@utcDT, @usersTimezone)

y

DECLARE @usersTimezone VARCHAR(32)='Europe/London'
DECLARE @userDT DATETIME=GetDate()
DECLARE @utcDT DATETIME=[dbo].[funcLocaltoUTC](@userDT, @usersTimezone)

Las funciones pueden admitir todas o un subconjunto de zonas horarias en IANA / TZDB según lo proporciona NodaTime; consulte la lista completa en https://nodatime.org/TimeZones

Tenga en cuenta que mi caso de uso significa que solo necesito una ventana 'actual', lo que permite la conversión de tiempos dentro del rango de aproximadamente +/- 5 años a partir de ahora. Esto significa que el método que he usado probablemente no sea adecuado para usted si necesita un período de tiempo muy amplio, debido a la forma en que genera código para cada intervalo de zona horaria en un rango de fechas determinado.

El proyecto está en GitHub: https://github.com/elliveny/SQLServerTimeConversion

Esto genera código de función SQL según este ejemplo


0

Bueno, si almacena los datos como fecha UTC en la base de datos, puede hacer algo tan simple como

select 
 [MyUtcDate] + getdate() - getutcdate()
from [dbo].[mytable]

esto era siempre local desde el punto del servidor y no estás jugando con AT TIME ZONE 'your time zone name', si tu base de datos se mueve a otra zona horaria como la instalación de un cliente, una zona horaria codificada podría morderte.


0

En postgres esto funciona muy bien ... Dígale al servidor la hora a la que se guarda la hora, 'utc', y luego pídale que se convierta a una zona horaria específica, en este caso 'Brasil / Este'

quiz_step_progresses.created_at  at time zone 'utc' at time zone 'Brazil/East'

Obtenga una lista completa de zonas horarias con la siguiente selección;

select * from pg_timezone_names;

Ver detalles aquí.

https://popsql.com/learn-sql/postgresql/how-to-convert-utc-to-local-time-zone-in-postgresql


-1

Aquí hay uno más simple que tiene en cuenta dst

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

66
En realidad, esto no tiene en cuenta el horario de verano. Haga la prueba: SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE()). Actualmente estoy en CEST (UTC + 2), pero el horario de verano no estará vigente el día de Año Nuevo, por lo que la respuesta correcta para mí sería el 1 de enero de 2015 a las 01:00. Su respuesta, como la respuesta aceptada, devuelve el 1 de enero de 2015 a las 02:00.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.