我正在做一些SQL选择查询,并希望将我的UTC日期时间列转换为本地时间,以便在我的查询结果中显示为本地时间。注意,我不希望通过代码进行这种转换,而是当我对我的数据库进行手动和随机SQL查询时。
当前回答
如果您将数据存储为UTC日期在数据库中,您可以做一些简单的事情
select
[MyUtcDate] + getdate() - getutcdate()
from [dbo].[mytable]
这是从服务器的角度来看,它总是本地的,你不会笨拙地使用AT TIME ZONE '你的时区名称', 如果您的数据库像客户端安装一样被移动到另一个时区,那么硬编码的时区可能会让您感到困扰。
其他回答
第一个功能:配置为意大利时区(+1,+2),切换日期:3月和10月的最后一个星期天,返回当前时区与datetime的差值作为参数。
Returns:
current timezone < parameter timezone ==> +1
current timezone > parameter timezone ==> -1
else 0
代码是:
CREATE FUNCTION [dbo].[UF_ADJUST_OFFSET]
(
@dt_utc datetime2(7)
)
RETURNS INT
AS
BEGIN
declare @month int,
@year int,
@current_offset int,
@offset_since int,
@offset int,
@yearmonth varchar(8),
@changeoffsetdate datetime2(7)
declare @lastweek table(giorno datetime2(7))
select @current_offset = DATEDIFF(hh, GETUTCDATE(), GETDATE())
select @month = datepart(month, @dt_utc)
if @month < 3 or @month > 10 Begin Set @offset_since = 1 Goto JMP End
if @month > 3 and @month < 10 Begin Set @offset_since = 2 Goto JMP End
--If i'm here is march or october
select @year = datepart(yyyy, @dt_utc)
if @month = 3
Begin
Set @yearmonth = cast(@year as varchar) + '-03-'
Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
(@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')
--Last week of march
Select @changeoffsetdate = giorno From @lastweek Where datepart(weekday, giorno) = 1
if @dt_utc < @changeoffsetdate
Begin
Set @offset_since = 1
End Else Begin
Set @offset_since = 2
End
End
if @month = 10
Begin
Set @yearmonth = cast(@year as varchar) + '-10-'
Insert Into @lastweek Values(@yearmonth + '31 03:00:00.000000'),(@yearmonth + '30 03:00:00.000000'),(@yearmonth + '29 03:00:00.000000'),(@yearmonth + '28 03:00:00.000000'),
(@yearmonth + '27 03:00:00.000000'),(@yearmonth + '26 03:00:00.000000'),(@yearmonth + '25 03:00:00.000000')
--Last week of october
Select @changeoffsetdate = giorno From @lastweek Where datepart(weekday, giorno) = 1
if @dt_utc > @changeoffsetdate
Begin
Set @offset_since = 1
End Else Begin
Set @offset_since = 2
End
End
JMP:
if @current_offset < @offset_since Begin
Set @offset = 1
End Else if @current_offset > @offset_since Set @offset = -1 Else Set @offset = 0
Return @offset
END
然后是转换日期的函数
CREATE FUNCTION [dbo].[UF_CONVERT]
(
@dt_utc datetime2(7)
)
RETURNS datetime
AS
BEGIN
declare @offset int
Select @offset = dbo.UF_ADJUST_OFFSET(@dt_utc)
if @dt_utc >= '9999-12-31 22:59:59.9999999'
set @dt_utc = '9999-12-31 23:59:59.9999999'
Else
set @dt_utc = (SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), @dt_utc) )
if @offset <> 0
Set @dt_utc = dateadd(hh, @offset, @dt_utc)
RETURN @dt_utc
END
declare @mydate2 datetime
set @mydate2=Getdate()
select @mydate2 as mydate,
dateadd(minute, datediff(minute,getdate(),@mydate2),getutcdate())
这可以在没有函数的情况下完成。下面的代码将把UTC时间转换为考虑夏令时的山地时间。相应地调整所有的-6和-7数字到您的时区(即对于EST,您将分别调整为-4和-5)
--Adjust a UTC value, in the example the UTC field is identified as UTC.Field, to account for daylight savings time when converting out of UTC to Mountain time.
CASE
--When it's between March and November, it is summer time which is -6 from UTC
WHEN MONTH ( UTC.Field ) > 3 AND MONTH ( UTC.Field ) < 11
THEN DATEADD ( HOUR , -6 , UTC.Field )
--When its March and the day is greater than the 14, you know it's summer (-6)
WHEN MONTH ( UTC.Field ) = 3
AND DATEPART ( DAY , UTC.Field ) >= 14
THEN
--However, if UTC is before 9am on that Sunday, then it's before 2am Mountain which means it's still Winter daylight time.
CASE
WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1
AND UTC.Field < '9:00'
--Before 2am mountain time so it's winter, -7 hours for Winter daylight time
THEN DATEADD ( HOUR , -7 , UTC.Field )
--Otherwise -6 because it'll be after 2am making it Summer daylight time
ELSE DATEADD ( HOUR , -6 , UTC.Field )
END
WHEN MONTH ( UTC.Field ) = 3
AND ( DATEPART ( WEEKDAY , UTC.Field ) + 7 ) <= DATEPART ( day , UTC.Field )
THEN
--According to the date, it's moved onto Summer daylight, but we need to account for the hours leading up to 2am if it's Sunday
CASE
WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1
AND UTC.Field < '9:00'
--Before 9am UTC is before 2am Mountain so it's winter Daylight, -7 hours
THEN DATEADD ( HOUR , -7 , UTC.Field )
--Otherwise, it's summer daylight, -6 hours
ELSE DATEADD ( HOUR , -6 , UTC.Field )
END
--When it's November and the weekday is greater than the calendar date, it's still Summer so -6 from the time
WHEN MONTH ( UTC.Field ) = 11
AND DATEPART ( WEEKDAY , UTC.Field ) > DATEPART ( DAY , UTC.Field )
THEN DATEADD ( HOUR , -6 , UTC.Field )
WHEN MONTH ( UTC.Field ) = 11
AND DATEPART ( WEEKDAY , UTC.Field ) <= DATEPART ( DAY , UTC.Field )
--If the weekday is less than or equal to the calendar day it's Winter daylight but we need to account for the hours leading up to 2am.
CASE
WHEN DATEPART ( WEEKDAY , UTC.Field ) = 1
AND UTC.Field < '8:00'
--If it's before 8am UTC and it's Sunday in the logic outlined, then it's still Summer daylight, -6 hours
THEN DATEADD ( HOUR , -6 , UTC.Field )
--Otherwise, adjust for Winter daylight at -7
ELSE DATEADD ( HOUR , -7 , UTC.Field )
END
--If the date doesn't fall into any of the above logic, it's Winter daylight, -7
ELSE
DATEADD ( HOUR , -7 , UTC.Field )
END
对于任何仍然试图解决这个问题的人,这里有一个在SQL Server 2017中工作的概念证明
declare
@StartDate date = '2020-01-01'
;with cte_utc as
(
select
1 as i
,CONVERT(datetime, @StartDate) AS UTC
,datepart(weekday, CONVERT(datetime, @StartDate)) as Weekday
,datepart(month, CONVERT(datetime, @StartDate)) as [Month]
,datepart(YEAR, CONVERT(datetime, @StartDate)) as [Year]
union all
Select
i + 1
,dateadd(d, 1, utc)
,datepart(weekday, CONVERT(datetime, dateadd(d, 1, utc))) as Weekday
,datepart(month, CONVERT(datetime, dateadd(d, 1, utc))) as [Month]
,datepart(YEAR, CONVERT(datetime, dateadd(d, 1, utc))) as [Year]
from
cte_utc
where
(i + 1) < 32767
), cte_utc_dates as
(
select
*,
DENSE_RANK()OVER(PARTITION BY [Year], [Month], [Weekday] ORDER BY Utc) WeekDayIndex
from
cte_utc
), cte_hours as (
select 0 as [Hour]
union all
select [Hour] + 1 from cte_hours where [Hour] < 23
)
select
d.*
, DATEADD(hour, h.Hour, d.UTC) AS UtcTime
,CONVERT(datetime, DATEADD(hour, h.Hour, d.UTC) AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time') CST
,CONVERT(datetime, DATEADD(hour, h.Hour, d.UTC) AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time') EST
from
cte_utc_dates d, cte_hours h
where
([Month] = 3 and [Weekday] = 1 and WeekDayIndex = 2 )-- dst start
or
([Month] = 11 and [Weekday] = 1 and WeekDayIndex = 1 )-- dst end
order by
utc
OPTION (MAXRECURSION 32767)
GO
我使用switchoffset将utc时间转换为本地时间。时区偏移可以通过使用datename(tzoffset,systemdatetimeoffset())来确定。同样地,如果您想获得经过的时间,则使用getutcdate将时间保持为datediff函数的utc时间。
select
,[Field1]
,Format(SWITCHOFFSET([MyDateOnUTC],DATENAME(TZOFFSET, SYSDATETIMEOFFSET())),'MM/dd/yyyy hh:mm:ss tt') UtcToLocalTime
,datediff(minute,[ClaimedOnUTC],getutcdate()) ElapsedMinutes
from dbo.my_table
推荐文章
- 如何在Ruby On Rails中使用NuoDB手动执行SQL命令
- 查询JSON类型内的数组元素
- 确定记录是否存在的最快方法
- 获得PostgreSQL数据库中当前连接数的正确查询
- 在SQL选择语句Order By 1的目的是什么?
- 从现有模式生成表关系图(SQL Server)
- 我如何循环通过一组记录在SQL Server?
- 数据库和模式的区别
- 如何在SQL Server中一次更改多个列
- 如何从命令行通过mysql运行一个查询?
- 外键约束可能导致循环或多条级联路径?
- 使用LIMIT/OFFSET运行查询,还可以获得总行数
- 当恢复sql时,psql无效命令\N
- 货币应该使用哪种数据类型?
- 如何选择每一行的列值不是独特的