TSQL: как конвертировать местное время в UTC? (SQL Server 2008)
мы имеем дело с приложением, которое должно обрабатывать глобальные данные времени из разных часовых поясов и настроек летнего времени. Идея состоит в том, чтобы хранить все в формате UTC внутренне и только конвертировать туда и обратно для локализованных пользовательских интерфейсов. Предлагает ли SQL Server какие-либо механизмы для обработки переводов с учетом времени, страны и часового пояса?
Это должно быть общая проблема, поэтому я удивлен, что google ничего не обнаружил годный.
какие-нибудь советы?
10 ответов:
7 лет...
на самом деле есть эта новая функция SQL Server 2016, которая делает именно то, что вам нужно.
Он вызывается в часовом поясе и преобразует дату в указанный часовой пояс с учетом изменений DST (летнее время).
Подробнее здесь: https://msdn.microsoft.com/en-us/library/mt612795.aspx
это работает для дат, которые в настоящее время имеют то же смещение UTC, что и узел SQL Server; он не учитывает изменения летнего времени. Заменить
YOUR_DATE
с локальной датой для преобразования.
SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);
хотя некоторые из этих ответов приведут вас в поле зрения, вы не можете делать то, что вы пытаетесь сделать с произвольными датами для SqlServer 2005 и ранее из-за летнего времени. Использование разницы между текущим локальным и текущим UTC даст мне смещение, как оно существует сегодня. Я не нашел способа определить, какое смещение было бы для рассматриваемой даты.
тем не менее, я знаю, что SqlServer 2008 предоставляет некоторые новые функции даты, которые могут устраните эту проблему, но люди, использующие более раннюю версию, должны знать об ограничениях.
наш подход заключается в сохранении UTC и выполнении преобразования на стороне клиента, где у нас есть больше контроля над точностью преобразования.
среда SQL Server 2008 имеет тип
datetimeoffset
. Это действительно полезно для такого рода вещей.http://msdn.microsoft.com/en-us/library/bb630289.aspx
затем вы можете использовать функцию
SWITCHOFFSET
чтобы переместить его из одного часового пояса в другой, но все еще сохраняя то же значение UTC.http://msdn.microsoft.com/en-us/library/bb677244.aspx
Роб
Вы можете использовать мой поддержка часового пояса SQL Server проект для преобразования между стандартными часовыми поясами IANA,как указано здесь.
UTC для локального выглядит так:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')
Local to UTC выглядит так:
SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1)
числовые параметры являются флагом для управления поведением, когда значения местного времени зависят от летнего времени. Они подробно описаны в проектной документации.
Я склоняюсь к использованию DateTimeOffset для всех хранилищ даты и времени, которые не связаны с локальным событием (т. е.: встреча/вечеринка и т. д., 12pm-3pm в музее).
чтобы получить текущий DTO в формате 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]
примечание: Я всегда буду использовать UTC при отправке по сети... на стороне клиента на JS можно легко добраться до/из местного мирового. Смотрите:
new Date().toJSON()
...следующий JS будет обрабатывать разбор даты UTC / GMT в формате ISO8601 для локального времени даты.
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; }; }
вот код для преобразования одной зоны
DateTime
в другую зонуDateTime
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
Примечание: это(
AT TIME ZONE
)работает только на SQL Server 2016+ и это преимущество автоматически учитывая дневной свет при преобразовании в определенный часовой пояс
да, в какой-то степени так подробно здесь.
Подход, который я использовал (до 2008 года), заключается в том, чтобы выполнить преобразование в бизнес-логике .NET перед вставкой в БД.
вы можете использовать функцию GETUTCDATE (), чтобы получить UTC datetime Вероятно, вы можете выбрать разницу между GETUTCDATE() и GETDATE () и использовать эту разницу для настройки ваших дат в UTC
но я согласен с предыдущим сообщением, что гораздо проще контролировать правильное время в бизнес-слое (например, в .NET).
пример использования:
SELECT Getdate=GETDATE() ,SysDateTimeOffset=SYSDATETIMEOFFSET() ,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0) ,GetutcDate=GETUTCDATE() GO
возвращает:
Getdate SysDateTimeOffset SWITCHOFFSET GetutcDate 2013-12-06 15:54:55.373 2013-12-06 15:54:55.3765498 -08:00 2013-12-06 23:54:55.3765498 +00:00 2013-12-06 23:54:55.373