[sql-server] TSQL : 현지 시간을 UTC로 변환하는 방법은 무엇입니까? (SQL Server 2008)

우리는 다른 시간대와 일광 절약 시간 설정의 글로벌 시간 데이터를 처리해야하는 응용 프로그램을 다루고 있습니다. 아이디어는 내부적으로 모든 것을 UTC 형식으로 저장하고 지역화 된 사용자 인터페이스에 대해서만 앞뒤로 변환하는 것입니다. SQL Server는 시간, 국가 및 시간대가 지정된 번역을 처리하기위한 메커니즘을 제공합니까?

이것은 일반적인 문제 일 것이므로 Google이 사용할 수있는 항목을 표시하지 않을 것이라는 점에 놀랐습니다.

포인터가 있습니까?



답변

7 년이 지났고
실제로 필요한 작업을 정확히 수행하는 새로운 SQL Server 2016 기능이 있습니다.
AT TIME ZONE이라고하며 서머 타임 (DST) 변경을 고려하여 날짜를 지정된 시간대로 변환합니다.
자세한 정보 :
https://msdn.microsoft.com/en-us/library/mt612795.aspx


답변

이것은 현재 SQL Server의 호스트와 동일한 UTC 오프셋을 가진 날짜에 대해 작동합니다. 일광 절약 시간 변경을 고려하지 않습니다. YOUR_DATE변환 할 현지 날짜로 바꿉니다 .

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


답변

이러한 답변 중 몇 가지가 당신을 구장에 가져다 줄 것이지만, 일광 절약 시간 때문에 SqlServer 2005 및 이전 버전에 대해 임의의 날짜로하려는 작업을 수행 할 수 없습니다. 현재 로컬과 현재 UTC의 차이를 사용하면 현재 존재하는 오프셋을 얻을 수 있습니다. 문제의 날짜에 대해 오프셋이 무엇 이었을지 결정하는 방법을 찾지 못했습니다.

즉, SqlServer 2008이이 문제를 해결할 수있는 몇 가지 새로운 날짜 기능을 제공한다는 것을 알고 있지만 이전 버전을 사용하는 사람들은 제한 사항을 알고 있어야합니다.

우리의 접근 방식은 UTC를 유지하고 변환의 정확성을 더 많이 제어 할 수있는 클라이언트 측에서 변환을 수행하는 것입니다.


답변

SQL Server 2016 이상 및 Azure SQL Database의 경우 기본 제공 AT TIME ZONE문을 사용합니다 .

이전 버전의 SQL Server의 경우 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)

숫자 옵션은 현지 시간 값이 일광 절약 시간의 영향을받는 경우 동작을 제어하기위한 플래그입니다. 이것들은 프로젝트 문서에 자세히 설명되어 있습니다.


답변

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


답변

다음은 한 영역 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+에서만 작동 하며 특정 시간대로 변환 할 때 자동으로 일광을 고려 한다는 장점이 있습니다.


답변

나는 지역 이벤트 (예 : 회의 / 파티 등, 박물관에서 12 pm-3pm)와 관련이없는 모든 날짜-시간 저장소에 DateTimeOffset을 사용하는 경향이 있습니다.

현재 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는 ISO8601 형식의 UTC / GMT 날짜를 로컬 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;
  };
}