web-dev-qa-db-ja.com

SQL Serverで夏時間の開始および終了関数を作成する方法

夏時間の開始日時と夏時間の終了日時を返す関数をSQLサーバーに作成する必要があります。

Webでいくつかの例を見つけましたが、それらはすべて3月1日と11月1日を使用しており、技術的には正しくありません。

夏時間は、3月の第2日曜日の午前2時に始まり、11月の第1日曜日の午前2時に終わります。

私は以下のコードから始めましたが、間違いだと確信しています。どんな援助も大歓迎です! :)

DECLARE @DSTSTART DATETIME

SELECT @DSTSTART = CASE WHEN 
DATEPART(MONTH, SYSDATETIME()) = 3
AND DATEPART(weekday, SYSDATETIME()) = 1
AND DATEDIFF(week,dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, SYSDATETIME()), 0)), 0), SYSDATETIME() - 1) = 2
AND DATEPART(HOUR, SYSDATETIME()) = 2
THEN SYSDATETIME()
END
RETURN (@DSTSTART)
END
GO
14
Amanda Brine

夏時間のスケジュールは国に応じて変化し、また年々変更される可能性があることを忘れないでください。たとえば、現在の米国のシステムは2007年に施行されました。

米国の現在のシステムが必要であると仮定した場合、特定の年に対する回答の1つの形式を次に示します。

SET DATEFIRST 7

DECLARE @year INT = 2013
DECLARE
    @StartOfMarch DATETIME ,
    @StartOfNovember DATETIME ,
    @DstStart DATETIME ,
    @DstEnd DATETIME



SET @StartOfMarch = DATEADD(MONTH, 2, DATEADD(YEAR, @year - 1900, 0))
SET @StartOfNovember = DATEADD(MONTH, 10, DATEADD(YEAR, @year - 1900, 0));
SET @DstStart = DATEADD(HOUR, 2,
                        DATEADD(day,
                                ( ( 15 - DATEPART(dw, @StartOfMarch) ) % 7 )
                                + 7, @StartOfMarch))
SET @DstEnd = DATEADD(HOUR, 2,
                      DATEADD(day,
                              ( ( 8 - DATEPART(dw, @StartOfNovember) ) % 7 ),
                              @StartOfNovember))


SELECT
    @DstStart AS DstStartInUS ,
    @DstEnd AS DstEndInUS

または関数として使用しますが、DateFirstが7に設定されていることを知っている必要があります。そうでない場合、数学はオフになります。

CREATE FUNCTION GetDstStart ( @Year AS INT )
RETURNS DATETIME
AS
    BEGIN

        DECLARE
            @StartOfMarch DATETIME ,
            @DstStart DATETIME 

        SET @StartOfMarch = DATEADD(MONTH, 2,
                                    DATEADD(YEAR, @year - 1900, 0))
        SET @DstStart = DATEADD(HOUR, 2,
                                DATEADD(day,
                                        ( ( 15 - DATEPART(dw,
                                                          @StartOfMarch) )
                                          % 7 ) + 7, @StartOfMarch))
        RETURN @DstStart
    END

GO;


CREATE FUNCTION GetDstEnd ( @Year AS INT )
RETURNS DATETIME
AS
    BEGIN
        DECLARE
            @StartOfNovember DATETIME ,
            @DstEnd DATETIME

        SET @StartOfNovember = DATEADD(MONTH, 10,
                                       DATEADD(YEAR, @year - 1900, 0))
        SET @DstEnd = DATEADD(HOUR, 2,
                              DATEADD(day,
                                      ( ( 8 - DATEPART(dw,
                                                       @StartOfNovember) )
                                        % 7 ), @StartOfNovember))
        RETURN @DstEnd
    END
17
Jamie F

個人的には、3月の第2日曜日を見つけるよりも11月の第1日曜日を見つける方が簡単だと思います。幸いなことに、一方を見つけた場合は、常に238日あるため、もう一方を見つけることができます。 Dstの終わりを見つけるための便利な関数は次のとおりです。

create function GetDstEnd (
                           @Year int
                          )
returns datetime
as
begin

   declare @DstEnd datetime;

   ;with FirstWeekOfNovember
   as (
       select top(7)
              cast(@Year as char(4))
            + '-11-0'
            + cast(row_number() over(order by object_id) as char(1))
            + ' 02:00:00'
              'DST_Stops'
         from sys.columns
      )
   select @DstEnd = DST_Stops
     from FirstWeekOfNovember
    where datepart(weekday,DST_Stops) = 1

   return @DstEnd;

end;

現在、Dstの開始は同じ機能で、わずか238日前です。

create function GetDstStart (
                             @Year int
                            )
returns datetime
as
begin;

   declare @DstStart datetime;

   ;with FirstWeekOfNovember
   as (
       select top(7)
              cast(@Year as char(4))
            + '-11-0'
            + cast(row_number() over(order by object_id) as char(1))
            + ' 02:00:00'
              'DST_Stops'
         from sys.columns
      )
   select @DstStart = dateadd(day,-238,DST_Stops)
     from FirstWeekOfNovember
    where datepart(weekday,DST_Stops) = 1

   return @DstStart;

end;
go
5
Brian Stork

SQL Serverバージョン2016は、この問題を解決します 一度限り 。以前のバージョンでは、おそらくCLRソリューションが最も簡単です。または、特定のDSTルール(USのみなど)の場合、T-SQL関数は比較的単純です。

ただし、一般的なT-SQLソリューションが可能になると思います。限り xp_regread動作します、これを試してください:

CREATE TABLE #tztable (Value varchar(50), Data binary(56));
DECLARE @tzname varchar(150) = 'SYSTEM\CurrentControlSet\Control\TimeZoneInformation'
EXEC master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @tzname, 'TimeZoneKeyName', @tzname OUT;
SELECT @tzname = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\' + @tzname
INSERT INTO #tztable
EXEC master.dbo.xp_regread 'HKEY_LOCAL_MACHINE', @tzname, 'TZI';
SELECT                                                                                  -- See http://msdn.Microsoft.com/ms725481
 CAST(CAST(REVERSE(SUBSTRING(Data,  1, 4)) AS binary(4))      AS int) AS BiasMinutes,   -- UTC = local + bias: > 0 in US, < 0 in Europe!
 CAST(CAST(REVERSE(SUBSTRING(Data,  5, 4)) AS binary(4))      AS int) AS ExtraBias_Std, --   0 for most timezones
 CAST(CAST(REVERSE(SUBSTRING(Data,  9, 4)) AS binary(4))      AS int) AS ExtraBias_DST, -- -60 for most timezones: DST makes UTC 1 hour earlier
 -- When DST ends:
 CAST(CAST(REVERSE(SUBSTRING(Data, 13, 2)) AS binary(2)) AS smallint) AS StdYear,       -- 0 = yearly (else once)
 CAST(CAST(REVERSE(SUBSTRING(Data, 15, 2)) AS binary(2)) AS smallint) AS StdMonth,      -- 0 = no DST
 CAST(CAST(REVERSE(SUBSTRING(Data, 17, 2)) AS binary(2)) AS smallint) AS StdDayOfWeek,  -- 0 = Sunday to 6 = Saturday
 CAST(CAST(REVERSE(SUBSTRING(Data, 19, 2)) AS binary(2)) AS smallint) AS StdWeek,       -- 1 to 4, or 5 = last <DayOfWeek> of <Month>
 CAST(CAST(REVERSE(SUBSTRING(Data, 21, 2)) AS binary(2)) AS smallint) AS StdHour,       -- Local time
 CAST(CAST(REVERSE(SUBSTRING(Data, 23, 2)) AS binary(2)) AS smallint) AS StdMinute,
 CAST(CAST(REVERSE(SUBSTRING(Data, 25, 2)) AS binary(2)) AS smallint) AS StdSecond,
 CAST(CAST(REVERSE(SUBSTRING(Data, 27, 2)) AS binary(2)) AS smallint) AS StdMillisec,
 -- When DST starts:
 CAST(CAST(REVERSE(SUBSTRING(Data, 29, 2)) AS binary(2)) AS smallint) AS DSTYear,       -- See above
 CAST(CAST(REVERSE(SUBSTRING(Data, 31, 2)) AS binary(2)) AS smallint) AS DSTMonth,
 CAST(CAST(REVERSE(SUBSTRING(Data, 33, 2)) AS binary(2)) AS smallint) AS DSTDayOfWeek,
 CAST(CAST(REVERSE(SUBSTRING(Data, 35, 2)) AS binary(2)) AS smallint) AS DSTWeek,
 CAST(CAST(REVERSE(SUBSTRING(Data, 37, 2)) AS binary(2)) AS smallint) AS DSTHour,
 CAST(CAST(REVERSE(SUBSTRING(Data, 39, 2)) AS binary(2)) AS smallint) AS DSTMinute,
 CAST(CAST(REVERSE(SUBSTRING(Data, 41, 2)) AS binary(2)) AS smallint) AS DSTSecond,
 CAST(CAST(REVERSE(SUBSTRING(Data, 43, 2)) AS binary(2)) AS smallint) AS DSTMillisec
FROM #tztable;
DROP TABLE #tztable

(複雑な)T-SQL関数は、 このデータ を使用して、現在のDSTルール中のすべての日付の正確なオフセットを決定できます。

3

UTCを現地時間に変換するためにオンラインで見つけたソリューションのどれにも本当に満足していなかったので、この機能を思いつきました。 私のSOここに答えてください を見てください

DSTが使用する標準の日付範囲に基づいて夏時間を有効にするかどうかを計算するロジックがあります(3月の第2日曜日の午前2時、時計は進みます; 11月の第1日曜日は標準時間に戻ります)

0
Adam Hey