Перетворити стовпець Datetime з UTC у місцевий час у select оператор


208

Я виконую кілька запитів вибору SQL і хотів би перетворити свій стовпець часу UTC у місцевий час, щоб він відображався як місцевий час у результатах мого запиту. Зауважте, я НЕ шукаю робити це перетворення за допомогою коду, а навпаки, коли я роблю вручну та випадкові запити SQL проти моїх баз даних.


Чи здається це питання подібним до ваших обставин? stackoverflow.com/questions/3404646/…
Taryn East

Відповіді:


322

Це можна зробити так, як на SQL Server 2008 або вище:

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

Ви також можете зробити менш докладно:

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

Що б ви не робили, не використовуйте -для віднімання дат, оскільки операція не є атомною, і ви будете отримувати невизначені результати через умови перегонів між системною датою та місцевою датою, яка перевіряється в різний час (тобто неатомічно) .

Зауважте, що ця відповідь не враховує DST. Якщо ви хочете включити коригування DST, будь ласка, дивіться також наступне запитання SO:

Як створити функцію початку та кінця літнього часу в SQL Server


38
Чи є спосіб зробити цей рахунок для заощадження денного світла?
Стів

15
Я не бачу тут назви часового поясу, тому це неправильно. Дуже
гарно

7
@MichaelGoldshteyn, якщо у вас є зміщення часового поясу, ви все ще не знаєте, в якому логічному часовому поясі знаходиться час. Зсув часового поясу може бути різним у різні моменти часу / історії (літній час є загальним). Ви компенсуєте час поточним зміщенням від UTC ... Наступним моментом є те, що це надасть часовий пояс серверу, а не клієнту, що може стати додатковою проблемою, якщо ви хостите в іншій країні.
JonnyRaa

4
@Niloofar Проста відповідь полягає в тому, що ти цього не робиш і не повинен. Час дат завжди повинен зберігатися в UTC (бажано, базуючись на тактовій частоті сервера бази даних, а не на сервері веб-сервера, сервері додатків і, безумовно, не на годиннику клієнта). Відображення цього часу - це функція для рівня користувальницького інтерфейсу, і він відповідає за перетворення часу в потрібний формат (включаючи часовий пояс, якщо це необхідно).
Роберт Маккі

11
Для тих, хто використовує sql azure, цей підхід не буде працювати, оскільки функції дати / часу всі повертають UTC, тому порівняння GETDATE () з GETUTCDATE () не дає вам нічого працювати, і ваш результат такий же, як і ви починали.
Брайан Суровец

59

Я не знайшов жодного з цих прикладів корисним для отримання часу, який зберігається як UTC, до дати у визначеному часовому поясі (НЕ часовий пояс сервера, оскільки бази даних Azure SQL працюють як UTC). Ось як я впорався. Це не елегантно, але просто і дає правильну відповідь, не підтримуючи інші таблиці:

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

4
Працює лише за 2016 рік та використовує системний реєстр. Але прекрасне рішення для Azure.
Ден Кюнді

2
Цей працює в лазурні часи, що зберігаються в UTC, дякую хлопці
Null

3
Ось список рядків, які можна використовувати для часових поясів: stackoverflow.com/a/7908482/631277
Метт Кемп,

1
Якщо ви використовуєте SQL 2016 та AT TIME ZONEсинтаксис, врахуйте stackoverflow.com/a/44941536/112764 - ви можете зв'язати кілька конверсій разом, просто об'єднавши кілька at time zone <blah>s.
NateJ

3
Це теж трохи дивно, але виглядає те, що дуже базове тестування також може спрацювати dateTimeField AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'- просто ланцюжок AT TIME ZONEтверджень. (@NateJ згадував це вище, я бачу зараз)
Девід Мохундро

22

Якщо ваш місцевий час дати скажіть, Eastern Standard Timeі ви хочете перетворити з UTC на це, то в Azure SQL і SQL Server 2016 і вище, ви можете зробити:

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

Повний список назв часових поясів можна знайти за допомогою:

SELECT * FROM sys.time_zone_info 

І так, часові пояси названі погано - навіть якщо це так Eastern Standard Time, економія денного світла враховується.


2
Часові пояси та зсуви також можна знайти на SQL Server тут: ВИБІР * ВІД sys.time_zone_info
rayzinnz

21

Якщо вам потрібна конверсія, окрім місця розташування вашого сервера, ось функція, яка дозволяє передавати стандартне зміщення та облікові записи на американський літній час:

-- =============================================
-- 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
Рон Сміт Я знаю, що це стара публікація, але мені було цікаво, що жорстко закодовані '0314' та '1107' представляють при отриманні діапазону DST. Здається, важко закодовані дні, які змінюються через DTS. Чому б ви важко кодували це, коли це має бути розрахункова дата, оскільки дні змінюються залежно від того, де на календарі припадає друга неділя березня та перша неділя листопада. Важко закодовані дні зробили б цей код принципово хибним.
Майк

2
Добре запитання :) Це максимальні дати, коли може відбутися друга неділя березня та перша неділя листопада. Наступні рядки встановлюють змінні на фактичну дату.
Рон Сміт

8

Використання нових можливостей 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

Але процедура clr працює в 5 разів швидше: '- (

Зверніть увагу, що зміщення для однієї TimeZone може змінитися на зимовий або літній час. Наприклад

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'

результати:

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

Не можна просто додавати постійне зміщення.


5

Якщо включення CLR у вашій базі даних є опцією, а також використанням часового поясу сервера sql, це можна записати у .Net досить легко.

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());
    }
}

Здійснюється значення datetime UTC, і виходить місцеве значення timetime щодо сервера. Нульові значення повертають нульові.


5

Немає простого способу зробити це правильним І загальним способом.

Перш за все, слід розуміти, що зміщення залежить від конкретної дати, часової зони та літнього часу. GetDate()-GetUTCDateсьогодні дає лише компенсацію на TZ сервера, що не стосується.

Я бачив лише два робочих рішення і багато шукаю.

1) Спеціальна функція SQL з парою таблиць базових даних, таких як часові зони та правила DST на TZ. Працюючий, але не дуже елегантний. Я не можу розмістити його, оскільки не володію кодом.

EDIT: Ось приклад цього методу https://gist.github.com/drumsta/16b79cee6bc195cd89c8

2) Додайте до .b збірку в db, .Net це може зробити дуже легко. Це працює дуже добре, але недоліком є ​​те, що вам потрібно налаштувати кілька параметрів на рівні сервера, і конфігурація легко порушується, наприклад, якщо ви відновите базу даних. Я використовую цей метод, але не можу його опублікувати, оскільки не володію кодом.


4

Жодне з них не працювало для мене, але це нижче працювало на 100%. Сподіваюся, це може допомогти іншим, хто намагається перетворити його таким, як я був.

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
Це має бути прийнятою відповіддю. Єдине, що я міняв би - це ім'я, оскільки це означає, що це час EST, коли це дійсно місцевий час, і StandardOffset передається як параметр.
Грег Гум

Погодьтеся, найкраща відповідь ... але замість того, щоб передати зміщення як параметр, я додав це в тіло функції:declare @StandardOffset int = datediff (hh, GETUTCDATE(), GETDATE())
Том Уорфілд

Слідкуючи за моєю попередньою пропозицією - Якщо ви обчислюєте @StandardOffset, то вам не потрібно робити корекцію DST.
Том

3

Ось версія, яка враховує економію денного світла, зміщення UTC, і не замикається на конкретний рік.

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

Я знайшов спосіб одноразового функціонування занадто повільним, коли є багато даних. Тому я це зробив, приєднавшись до функції таблиці, яка дозволила б обчислити розрив години. Це в основному сегменти дати з компенсацією за годину. Рік складе 4 ряди. Отже функція таблиці

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

поверне цю таблицю:

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

Це враховує економію денного світла. Зразок способу його використання наведено нижче, а повна публікація блогу - тут .

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

Здається, не вважати DST правильно. Не впевнений, якщо ви припускаєте, що існує лише США, і що правила DST ніколи не змінюються.
vikjon0

@ vikjon0 так, проект, для якого я створив, мав лише часові пояси в США.
JBrooks

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

1

Відповідь Рона містить помилку. Він використовує 02:00 за місцевим часом, коли потрібен еквівалент UTC. У мене не вистачає репутаційних точок, щоб коментувати відповідь Рона, тож виправлена ​​версія з'являється нижче:

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

Це особливість, а не помилка :) Більшість Сполучених Штатів починає літній час о 02:00. En.wikipedia.org/wiki/Daylight_saving_time
Рон Сміт

@RonSmith Так, о 2:00 за місцевим часом, який ми маємо перетворити на UTC, щоб виявити, чи вказаний час UTC знаходиться в діапазоні DST.
jlspublic

1

Мітка часу UNIX - це лише кількість секунд між певною датою та епохою Unix,

SELECT DATEDIFF (SECOND, {d '1970-01-01'}, GETDATE ()) // Це поверне часову позначку UNIX на SQL-сервері

ви можете створити функцію для локального часу перетворення в Unix UTC перетворення, використовуючи функцію зміщення країни в часовий штамп Unix на сервері SQL


1

Це просто. Спробуйте це для Azure SQL Server:

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

Для локального SQL-сервера:

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

1
Що відбувається з цим під час літнього часу (оскільки в часовому поясі спеціально сказано "Східний стандартний час")?
Марк

1

Для користувачів Azure SQL та @@Version> = користувачів SQL Server 2016, нижче наведена проста функція 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

Для типів значень, які @LocalTimeZoneможна прийняти, перейдіть за цим посиланням або Перейдіть доKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones


0

Як попередження - якщо ви збираєтесь використовувати наступне (зверніть увагу на мілісекунди замість хвилин):

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

Майте на увазі, що частина DATEDIFF не завжди повертає однакове число. Тому не використовуйте його для порівняння DateTimes до мілісекунд.


0

Я виявив, що ця функція швидша, ніж інші рішення, використовуючи окрему таблицю або цикли. Це просто основний випадок справи. Зважаючи на те, що всі місяці між квітнем та жовтнем мають зміщення на 4 години (східний час), нам просто потрібно додати ще декілька ліній справ за межі днів. В іншому випадку компенсація становить -5 годин.

Це характерно для переходу з UTC у східний час, але додаткові функції часового поясу можна додавати за потреби.

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

Це повинно мати можливість отримати серверний час за допомогою DST

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

sysdatetimeoffset враховує DST

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

0

Перша функція: налаштована на італійський часовий пояс (+1, +2), переключіть дати: остання неділя березня та жовтень, поверніть різницю між поточним часовим поясом та датою як параметр.

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

Код:

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

Потім функція, яка перетворює дату

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

- отримати індійський стандартний час від utc

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

    RETURN dateadd(minute,330,@UTCDate)

END
GO

0

Це можна зробити без функції. Код нижче перетворить час UTC на гірський час з урахуванням економії літнього часу. Відповідно відрегулюйте всі цифри -6 та -7 до часового поясу (тобто для EST ви налаштували відповідно -4 та -5)

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

Вам доведеться переформатувати рядок, а також перетворити на правильний час. У цьому випадку мені знадобився зулуський час.

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

Найкращий спосіб для Oracle:

З твердим кодом дати:

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

Імена стовпців та таблиць:

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

У мене є код для виконання UTC в локальний і локальний до UTC разів, який дозволяє конвертувати за допомогою такого коду

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

і

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

Функції можуть підтримувати всі або підмножину часових поясів в IANA / TZDB, як це передбачено NodaTime - див. Повний список за адресою https://nodatime.org/TimeZones

Будьте в курсі, що мій випадок використання означає, що мені потрібно лише "поточне" вікно, що дозволяє перетворити час у межах приблизно +/- 5 років відтепер. Це означає, що метод, який я використовував, ймовірно, не підходить для вас, якщо вам потрібен дуже широкий проміжок часу, через спосіб генерування коду для кожного інтервалу часового поясу в заданому діапазоні дат.

Проект працює на GitHub: https://github.com/elliveny/SQLServerTimeConversion

Це генерує код функції SQL відповідно до цього прикладу


0

Добре, якщо ви зберігаєте дані як дату UTC у базі даних, ви можете зробити щось настільки ж просто

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

це завжди локально з точки зору сервера, і ви не маретеся з AT TIME ZONE 'your time zone name', якщо ваша база даних буде переміщена в інший часовий пояс, як установка клієнта, важко закодований часовий пояс може вас укусити.


0

У postgres це працює дуже добре. Скажіть серверу час, в який зберігається час, "utc", а потім попросіть його перетворити на певний часовий пояс, у цьому випадку "Бразилія / Схід"

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

Отримайте повний перелік часових поясів із наступним вибором;

select * from pg_timezone_names;

Деталі дивіться тут.

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


-1

Ось простіший, який бере на облік dst

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

6
Це фактично не враховує DST. Просто спробуйте: SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, GETUTCDATE(), '20150101'), GETDATE()). Зараз я перебуваю на CEST (UTC + 2), але DST не діятиме в новорічний день, тому правильна відповідь для мене буде 1 січня 2015 01:00. Ваша відповідь, як і прийнята відповідь, повертається 1 січня 2015 02:00.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.