夏時間の開始日時と夏時間の終了日時を返す関数を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
夏時間のスケジュールは国に応じて変化し、また年々変更される可能性があることを忘れないでください。たとえば、現在の米国のシステムは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
個人的には、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
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ルール中のすべての日付の正確なオフセットを決定できます。
UTCを現地時間に変換するためにオンラインで見つけたソリューションのどれにも本当に満足していなかったので、この機能を思いつきました。 私のSOここに答えてください を見てください
DSTが使用する標準の日付範囲に基づいて夏時間を有効にするかどうかを計算するロジックがあります(3月の第2日曜日の午前2時、時計は進みます; 11月の第1日曜日は標準時間に戻ります)