Мы имеем дело с приложением, которое должно обрабатывать глобальные данные о времени из разных часовых поясов и настройки перехода на летнее время. Идея состоит в том, чтобы хранить все в формате UTC внутри и конвертировать только туда и обратно для локализованных пользовательских интерфейсов. Предлагает ли SQL Server какие-либо механизмы для работы с переводами с учетом времени, страны и часового пояса?
Это должно быть распространенная проблема, поэтому я удивлен, что Google не нашел ничего полезного.
Есть указатели?
sql-server
tsql
sql-server-2008
timezone
utc
BuschnicK
источник
источник
Ответы:
Прошло 7 лет, и ... на
самом деле появилась новая функция SQL Server 2016, которая делает именно то, что вам нужно.
Он называется AT TIME ZONE и преобразует дату в указанный часовой пояс с учетом изменений летнего времени (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 2016 и новее, а также для базы данных SQL Azure используйте встроенный
AT TIME ZONE
оператор .Для более старых выпусков SQL Server вы можете использовать мой проект поддержки часовых поясов SQL Server для преобразования между стандартными часовыми поясами IANA, как указано здесь .
UTC в 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)
Числовые параметры - это флаг для управления поведением, когда на значения местного времени влияет переход на летнее время. Они подробно описаны в документации по проекту.
источник
SQL Server 2008 имеет тип, называемый
datetimeoffset
. Это действительно полезно для такого рода вещей.http://msdn.microsoft.com/en-us/library/bb630289.aspx
Затем вы можете использовать эту функцию,
SWITCHOFFSET
чтобы переместить его из одного часового пояса в другой, сохраняя при этом то же значение UTC.http://msdn.microsoft.com/en-us/library/bb677244.aspx
Роб
источник
Вот код для преобразования одной зоны
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+, и преимущество состоит в том, что он автоматически учитывает дневной свет при преобразовании в определенный часовой пояс.источник
AT TIME ZONE
объединить несколько вызовов (фраз?) Вместе! Просто элегантно. Ранее я сказал, что stackoverflow.com/a/44579178/112764 отвечает моим потребностям, но это даже лучше. Большая честь.DECLARE @UTCDateTime DATETIME = GETUTCDATE();
DECLARE @ConvertedZoneDateTime DATETIME;
-- 'UTC' to 'India Standard Time' to 'Eastern Standard Time' DATETIME
SET @ConvertedZoneDateTime = @UTCDateTime AT TIME ZONE 'UTC' AT TIME ZONE 'India Standard Time' AT TIME ZONE 'Eastern Standard Time'
SELECT @UTCDateTime AS UTCDATE,@ConvertedZoneDateTime AS EasternStandardTime
Да, вы можете объединить несколькоAT TIME ZONE
вызовов в цепочку , но From и To достаточно для любой конверсии, и большинство из них нам нужноЯ склоняюсь к использованию DateTimeOffset для всего хранения даты и времени, которое не связано с местным событием (например, встреча / вечеринка и т. Д., С 12 до 15 в музее).
Чтобы получить текущий 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 в локальную дату и время.
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; }; }
источник
Да, в некоторой степени, как описано здесь .
Подход, который я использовал (до 2008 г.), - это преобразование в бизнес-логику .NET перед вставкой в БД.
источник
Вы можете использовать функцию GETUTCDATE (), чтобы получить дату и время в формате UTC. Возможно, вы можете выбрать разницу между GETUTCDATE () и GETDATE () и использовать эту разницу, чтобы скорректировать свои даты по UTC.
Но я согласен с предыдущим сообщением, что гораздо проще контролировать правильное datetime на бизнес-уровне (например, в .NET).
источник
Пример использования:
SELECT Getdate=GETDATE() ,SysDateTimeOffset=SYSDATETIMEOFFSET() ,SWITCHOFFSET=SWITCHOFFSET(SYSDATETIMEOFFSET(),0) ,GetutcDate=GETUTCDATE() GO
Возврат:
источник