Рассчитать время в указанных c Часовой пояс, от UT C Время - PullRequest
0 голосов
/ 09 января 2020

Я хочу вычислить Datetime в заданном часовом поясе на основе Datetime в UT C.

Я подумал, что могу сделать это со следующим:

DECLARE @timeUTC DATETIME = '2019-01-01 10:00:00'

SELECT 
@timeUTC AS timeUTC,
@timeUTC AT TIME ZONE 'Central European Standard Time' as at_time_zone_offset,
CONVERT(datetime, @timeUTC AT TIME ZONE 'Central European Standard Time',1) at_timezone_convert

-- OUTPUT
---timeUTC                  |at_time_zone_offset                |at_timezone_convert
---2019-01-01 10:00:00.000  |2019-01-01 10:00:00.000 +01:00     |2019-01-01 09:00:00.000

Проблема в том, что результат at_timezone_convert неверен - когда в UT C время равно 10:00, тогда время +1 равно 11:00, а не 9.

Как я могу получить результат, равный 2019-01 -01 11: 00: 00.000 ?

Ответы [ 4 ]

2 голосов
/ 09 января 2020

At time zone документация четко гласит:

Преобразует inputdate в соответствующее значение datetimeoffset в целевом часовом поясе. Когда inputdate предоставляется без информации о смещении, функция применяет смещение часового пояса, предполагая, что inputdate находится в целевом часовом поясе. Если inputdate предоставляется в качестве значения datetimeoffset, то предложение AT TIME ZONE преобразует его в целевой часовой пояс с использованием правил преобразования часовых поясов.

(выделено мной)

Если вы объявите @timeUTC как DateTimeOffset, а не как DateTime you ' Вы получите другие результаты - также обратите внимание, что после преобразования DateTimeOffset обратно в DateTime вы получите необычные результаты.

Также обратите внимание, что строковое представление yyyy-mm-dd hh:mm:ss Формат является локализованным форматом при работе с DateTime - это не относится к более новому типу данных DateTime2, что является еще одной причиной , почему вы никогда не должны снова работать с DateTime.

См. Демонстрацию по DB <> Fiddle

1 голос
/ 09 января 2020

Вот трюк, которым я пользуюсь время от времени:

DECLARE @ timeUT C DATETIME = '2019-01-01 10:00:00'

SELECT @ timeUTC AS timeUT C, @timeUTC AT TIME ZONE 'UT C' AT TIME ZONE 'Центрально-европейское стандартное время' как at_time_zone_offset

Почему это работает? К вашему исходному дате и времени нет прикрепленной информации о смещении (другие авторы здесь объяснили, что такое по умолчанию, когда это так). В первом предложении at time zone говорится SQL Сервер «это время и дата представляют время в UT C» и выводит тип данных datetimeoffset. Второе предложение at time zone затем говорит ему преобразовать его в желаемый часовой пояс.

1 голос
/ 09 января 2020

Предоставляя входные данные в виде datetimeoffset, AT TIME ZONE подсказка преобразуется во входные данные в целевой часовой пояс.

Ниже приведен простой пример:

DECLARE @Utc DATETIME = '2019-01-01 10:00:00';
DECLARE @UtcOffset datetimeoffset(7) = @Utc;

SELECT 
    @Utc Utc,
    @UtcOffset UtcOffset,
    @UtcOffset AT TIME ZONE 'Central European Standard Time' UtcConverted;

-- Results
-- Utc          1/1/2019 10:00:00 AM
-- UtcOffset    1/1/2019 10:00:00 AM +00:00
-- UtcConverted 1/1/2019 11:00:00 AM +01:00 
0 голосов
/ 09 января 2020

Зохар Пелед объяснил это просто отлично, но на всякий случай вот пример кода:

DECLARE @timeUTC DATETIME = '2019-01-01 10:00:00';

SELECT
    @timeUTC AS timeUTC,
    @timeUTC AT TIME ZONE 'Central European Standard Time' as at_time_zone_offset,
    CONVERT(datetime, cast (@timeUTC AT TIME ZONE 'Central European Standard Time' as datetimeoffset),1) at_timezone_convert,
    CAST(CAST(@timeUTC AS datetimeoffset) AT TIME ZONE 'Central European Standard Time' AS datetime) AS ResultYouNeeded;
...