将UTC日期时间转换为本地日期时间的最佳方法是什么.它不像getutcdate()和getdate()那样简单,因为差异会根据日期而变化.
CLR集成对我来说也不是一个选择.
几个月前我提出解决这个问题的解决方案就是有一个夏令时表,存储了接下来100年左右的开始和结束夏令时,这个解决方案似乎不太优雅,但转换很快(简单)表查找)
Eri*_*ard 27
创建两个表,然后加入它们以将存储的GMT日期转换为本地时间:
TimeZones e.g.
--------- ----
TimeZoneId 19
Name Eastern (GMT -5)
Offset -5
Run Code Online (Sandbox Code Playgroud)
创建夏令时表并尽可能多地填充信息(当地法律一直在变化,因此无法预测未来几年的数据)
DaylightSavings
---------------
TimeZoneId 19
BeginDst 3/9/2008 2:00 AM
EndDst 11/2/2008 2:00 AM
Run Code Online (Sandbox Code Playgroud)
像这样加入他们:
inner join TimeZones tz on x.TimeZoneId=tz.TimeZoneId
left join DaylightSavings ds on tz.TimeZoneId=ds.LocalTimeZone
and x.TheDateToConvert between ds.BeginDst and ds.EndDst
Run Code Online (Sandbox Code Playgroud)
转换这样的日期:
dateadd(hh, tz.Offset +
case when ds.LocalTimeZone is not null
then 1 else 0 end, TheDateToConvert)
Run Code Online (Sandbox Code Playgroud)
Bob*_*ght 15
如果您在美国并且只对从UTC/GMT到固定时区(例如EDT)感兴趣,则此代码应该足够了.我今天掀起了它,并认为这是正确的,但使用风险自负.
假设您的日期位于"日期"列中,则将计算列添加到表'myTable'.希望别人觉得这很有用.
ALTER TABLE myTable ADD date_edt AS
dateadd(hh,
-- The schedule through 2006 in the United States was that DST began on the first Sunday in April
-- (April 2, 2006), and changed back to standard time on the last Sunday in October (October 29, 2006).
-- The time is adjusted at 02:00 local time.
CASE WHEN YEAR(date) <= 2006 THEN
CASE WHEN
date >= '4/' + CAST(abs(8-DATEPART(dw,'4/1/' + CAST(YEAR(date) as varchar)))%7 + 1 as varchar) + '/' + CAST(YEAR(date) as varchar) + ' 2:00'
AND
date < '10/' + CAST(32-DATEPART(dw,'10/31/' + CAST(YEAR(date) as varchar)) as varchar) + '/' + CAST(YEAR(date) as varchar) + ' 2:00'
THEN -4 ELSE -5 END
ELSE
-- By the Energy Policy Act of 2005, daylight saving time (DST) was extended in the United States in 2007.
-- DST starts on the second Sunday of March, which is three weeks earlier than in the past, and it ends on
-- the first Sunday of November, one week later than in years past. This change resulted in a new DST period
-- that is four weeks (five in years when March has five Sundays) longer than in previous years.[35] In 2008
-- daylight saving time ended at 02:00 on Sunday, November 2, and in 2009 it began at 02:00 on Sunday, March 8.[36]
CASE WHEN
date >= '3/' + CAST(abs(8-DATEPART(dw,'3/1/' + CAST(YEAR(date) as varchar)))%7 + 8 as varchar) + '/' + CAST(YEAR(date) as varchar) + ' 2:00'
AND
date <
'11/' + CAST(abs(8-DATEPART(dw,'11/1/' + CAST(YEAR(date) as varchar)))%7 + 1 as varchar) + '/' + CAST(YEAR(date) as varchar) + ' 2:00'
THEN -4 ELSE -5 END
END
,date)
Run Code Online (Sandbox Code Playgroud)
小智 8
FOR READ-ONLY使用此(受Bob Albright错误解决方案的启发):
SELECT
date1,
dateadd(hh,
-- The schedule through 2006 in the United States was that DST began on the first Sunday in April
-- (April 2, 2006), and changed back to standard time on the last Sunday in October (October 29, 2006).
-- The time is adjusted at 02:00 local time (which, for edt, is 07:00 UTC at the start, and 06:00 GMT at the end).
CASE WHEN YEAR(date1) <= 2006 THEN
CASE WHEN
date1 >= '4/' + CAST((8-DATEPART(dw,'4/1/' + CAST(YEAR(date1) as varchar)))%7 + 1 as varchar) + '/' + CAST(YEAR(date1) as varchar) + ' 7:00'
AND
date1 < '10/' + CAST(32-DATEPART(dw,'10/31/' + CAST(YEAR(date1) as varchar)) as varchar) + '/' + CAST(YEAR(date1) as varchar) + ' 6:00'
THEN -4 ELSE -5 END
ELSE
-- By the Energy Policy Act of 2005, daylight saving time (DST) was extended in the United States in 2007.
-- DST starts on the second Sunday of March, which is three weeks earlier than in the past, and it ends on
-- the first Sunday of November, one week later than in years past. This change resulted in a new DST period
-- that is four weeks (five in years when March has five Sundays) longer than in previous years. In 2008
-- daylight saving time ended at 02:00 edt (06:00 UTC) on Sunday, November 2, and in 2009 it began at 02:00 edt (07:00 UTC) on Sunday, March 8
CASE WHEN
date1 >= '3/' + CAST((8-DATEPART(dw,'3/1/' + CAST(YEAR(date1) as varchar)))%7 + 8 as varchar) + '/' + CAST(YEAR(date1) as varchar) + ' 7:00'
AND
date1 < '11/' + CAST((8-DATEPART(dw,'11/1/' + CAST(YEAR(date1) as varchar)))%7 + 1 as varchar) + '/' + CAST(YEAR(date1) as varchar) + ' 6:00'
THEN -4 ELSE -5 END
END
, date1) as date1Edt
from MyTbl
Run Code Online (Sandbox Code Playgroud)
在我尝试编辑Bob Albright的错误答案后,我发布了这个答案.我纠正了时间并删除了多余的abs(),但我的编辑被多次拒绝了.我尝试解释,但被解雇为一个菜鸟.他是解决这个问题的绝佳方法!它让我开始朝着正确的方向前进.当他只需要一个小小的调整时,我讨厌创建这个单独的答案,但我试过了¯\ _(ツ)_ /¯
小智 7
考虑夏令时的更简单通用的解决方案.给定"YourDateHere"中的UTC日期:
--Use Minutes ("MI") here instead of hours because sometimes
-- the UTC offset may be half an hour (e.g. 9.5 hours).
SELECT DATEADD(MI,
DATEDIFF(MI, SYSUTCDATETIME(),SYSDATETIME()),
YourUtcDateHere)[LocalDateTime]
Run Code Online (Sandbox Code Playgroud)
如果这些问题中的任何一个对您有影响,则不应将本地时间存储在数据库中:
小智 5
在Eric Z Beard的回答中,以下是SQL
inner join TimeZones tz on x.TimeZoneId=tz.TimeZoneId
left join DaylightSavings ds on tz.TimeZoneId=ds.LocalTimeZone
and x.TheDateToConvert between ds.BeginDst and ds.EndDst
Run Code Online (Sandbox Code Playgroud)
可能更准确地说是:
inner join TimeZones tz on x.TimeZoneId=tz.TimeZoneId
left join DaylightSavings ds on tz.TimeZoneId=ds.LocalTimeZone
and x.TheDateToConvert >= ds.BeginDst and x.TheDateToConvert < ds.EndDst
Run Code Online (Sandbox Code Playgroud)
(以上代码未经测试)
原因是sql"between"语句是包含的.在DST的后端,这将导致2AM时间未转换为1AM.当然,时间2AM的可能性恰好很小,但它可能发生,并且会导致无效的转换.
归档时间: |
|
查看次数: |
65387 次 |
最近记录: |