TSQL: Как перевести местное время в UTC? (SQL Server 2008) - PullRequest
66 голосов
/ 30 июля 2009

Мы имеем дело с приложением, которое должно обрабатывать глобальные данные времени из разных часовых поясов и настройки летнего времени. Идея состоит в том, чтобы хранить все в формате UTC внутри и конвертировать только туда и обратно для локализованных пользовательских интерфейсов. Предлагает ли SQL Server какие-либо механизмы для работы с переводами с указанием времени, страны и часового пояса?

Это, должно быть, распространенная проблема, поэтому я удивлен, что Google не может найти ничего полезного.

Есть указатели?

Ответы [ 10 ]

57 голосов
/ 07 ноября 2010

Это работает для дат, которые в настоящее время имеют такое же смещение UTC, что и хост SQL Server; это не учитывает изменения летнего времени. Замените YOUR_DATE локальной датой для конвертации.

SELECT DATEADD(second, DATEDIFF(second, GETDATE(), GETUTCDATE()), YOUR_DATE);

33 голосов
/ 28 октября 2016

7 лет прошло и ...
на самом деле есть новая функция SQL Server 2016, которая делает именно то, что вам нужно.
Он называется AT TIME ZONE и преобразует дату в указанный часовой пояс, учитывая изменения летнего времени (DST).
Больше информации здесь: https://msdn.microsoft.com/en-us/library/mt612795.aspx

21 голосов
/ 14 октября 2011

Хотя некоторые из этих ответов приведут вас в примерное положение, вы не можете делать то, что пытаетесь сделать с произвольными датами для SqlServer 2005 и более ранних версий, из-за перехода на летнее время. Использование разницы между текущим локальным и текущим UTC даст мне смещение, существующее сегодня. Я не нашел способа определить, какое смещение было бы для рассматриваемой даты.

Тем не менее, я знаю, что SqlServer 2008 предоставляет некоторые новые функции даты, которые могут решить эту проблему, но люди, использующие более раннюю версию, должны знать об ограничениях.

Наш подход заключается в том, чтобы сохранить UTC и выполнить преобразование на стороне клиента, где мы можем лучше контролировать точность преобразования.

14 голосов
/ 03 апреля 2015

Вы можете использовать мой Проект поддержки часовых поясов 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)

Числовые параметры - это флаг для управления поведением, когда на летнее время влияют значения местного времени. Они подробно описаны в документации проекта.

14 голосов
/ 30 июля 2009

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

9 голосов
/ 06 июля 2017

Вот код для преобразования одной зоны 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 + , и преимущество в том, что автоматически учитывает дневной свет при преобразовании в определенный часовой пояс

4 голосов
/ 21 мая 2012

Я склоняюсь к использованию 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;
  };
}
3 голосов
/ 30 июля 2009

Да, в некоторой степени, как подробно здесь .
Подход, который я использовал (до 2008 года), заключается в том, чтобы выполнить преобразование в бизнес-логике .NET перед вставкой в ​​БД.

2 голосов
/ 30 июля 2009

Вы можете использовать функцию GETUTCDATE (), чтобы получить дату и время UTC Возможно, вы можете выбрать разницу между GETUTCDATE () и GETDATE () и использовать эту разницу, чтобы откорректировать ваши даты к UTC

Но я согласен с предыдущим сообщением, что намного проще контролировать правильную дату и время на бизнес-уровне (например, в .NET).

0 голосов
/ 07 декабря 2013

Пример использования:

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