TSQL: как конвертировать локальное время в UTC? (SQL Server 2008)
Мы имеем дело с приложением, которое должно обрабатывать глобальные данные времени из разных часовых поясов и летнего времени. Идея состоит в том, чтобы хранить все в формате UTC внутри и только конвертировать назад и вперед для локализованных пользовательских интерфейсов. Предлагает ли SQL Server какие-либо механизмы для работы с переводами с учетом времени, страны и часового пояса?
Это должна быть распространенная проблема, поэтому я удивлен, что Google не будет использовать что-нибудь пригодное для использования.
Любые указатели?
Ответы
Ответ 1
Прошло 7 лет и...
на самом деле это новая функция SQL Server 2016, которая делает именно то, что вам нужно.
Он называется AT TIME ZONE, и он преобразует дату в указанный часовой пояс, учитывая изменения DST (переход на летнее время).
Подробнее здесь:
https://msdn.microsoft.com/en-us/library/mt612795.aspx
Ответ 2
Это работает для дат, которые в настоящее время имеют одинаковое UTC-смещение как хост SQL Server; он не учитывает изменения дневного света. Замените YOUR_DATE
на локальную дату для преобразования.
SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);
Ответ 3
В то время как некоторые из этих ответов помогут вам в шаге, вы не можете делать то, что вы пытаетесь сделать с произвольными датами для SqlServer 2005 и ранее из-за летнего времени. Использование разницы между текущим местным и текущим UTC даст мне смещение, как оно существует сегодня. Я не нашел способа определить, какое смещение было бы для указанной даты.
Тем не менее, я знаю, что SqlServer 2008 предоставляет некоторые новые функции даты, которые могут решить эту проблему, но люди, использующие более раннюю версию, должны знать об ограничениях.
Наш подход заключается в сохранении UTC и выполнении конверсии на стороне клиента, где мы больше контролируем точность преобразования.
Ответ 4
SQL Server 2008 имеет тип datetimeoffset
. Это действительно полезно для этого типа вещей.
http://msdn.microsoft.com/en-us/library/bb630289.aspx
Затем вы можете использовать функцию SWITCHOFFSET
для перемещения ее из одного часового пояса в другой, но при этом сохраняя то же значение UTC.
http://msdn.microsoft.com/en-us/library/bb677244.aspx
Rob
Ответ 5
Вы можете использовать мой проект поддержки часовых поясов SQL Server для преобразования между стандартными часовыми поясами IANA, как указано здесь.
UTC to Local - это так:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles')
Локальный для UTC выглядит следующим образом:
SELECT Tzdb.LocalToUtc('2015-07-01 00:00:00', 'America/Los_Angeles', 1, 1)
Числовые параметры - это флаг для управления поведением, когда на локальные значения времени влияет летнее время. Они подробно описаны в проектной документации.
Ответ 6
Вот код для преобразования одной зоны 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+, и преимущество заключается в том, что он автоматически учитывает дневной свет при преобразовании в определенный часовой пояс
Ответ 7
Я склонен склоняться к использованию DateTimeOffset для всех хранилищ времени, которые не связаны с местным событием (например, встреча/вечеринка и т.д., 12 pm-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 может легко получить/с локального UTC. См.: new Date().toJSON()
...
Следующий JS будет обрабатывать разбор даты UTC/GMT в формате ISO8601 на локальное datetime.
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;
};
}
Ответ 8
Да, в некоторой степени, как описано ниже здесь.
Подход, который я использовал (до 2008 года), - это сделать преобразование в бизнес-логике .NET перед вставкой в БД.
Ответ 9
Вы можете использовать функцию GETUTCDATE() для получения времени UTC
Вероятно, вы можете выбрать разницу между GETUTCDATE() и GETDATE() и использовать эту разницу для привязки ваших дат к UTC
Но я согласен с предыдущим сообщением, что гораздо проще управлять правом datetime на бизнес-уровне (например, в .NET).
Ответ 10
Использование образца:
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