Nug*_*ugs 189 sql sql-server
我正在做一些SQL选择查询,并希望将我的UTC日期时间列转换为本地时间,以便在我的查询结果中显示为本地时间.注意,我不希望通过代码进行此转换,而是在我对数据库进行手动和随机SQL查询时.
Mic*_*eyn 296
您可以在SQL Server 2008或更高版本上执行以下操作:
SELECT CONVERT(datetime,
SWITCHOFFSET(CONVERT(datetimeoffset,
MyTable.UtcColumn),
DATENAME(TzOffset, SYSDATETIMEOFFSET())))
AS ColumnInLocalTime
FROM MyTable
Run Code Online (Sandbox Code Playgroud)
你也可以做一些不那么冗长的事情:
SELECT DATEADD(mi, DATEDIFF(mi, GETUTCDATE(), GETDATE()), MyTable.UtcColumn)
AS ColumnInLocalTime
FROM MyTable
Run Code Online (Sandbox Code Playgroud)
不管你做什么,不要使用-
减去日期,因为该操作不是原子操作,你会偶尔得到应有的种族系统日期时间与当地的日期时间之间的条件不确定的结果在不同的时间被检查(即非原子) .
请注意,此答案不考虑DST.如果您想要包含DST调整,请参阅以下SO问题:
Mat*_*ear 53
如果您说的是本地日期时间Eastern Standard Time
并且您想从 UTC 转换为该时间,那么在 Azure SQL 和 SQL Server 2016 及更高版本中,您可以执行以下操作:
SELECT YourUtcColumn AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time' AS
LocalTime
FROM YourTable
Run Code Online (Sandbox Code Playgroud)
可以通过以下方式找到时区名称的完整列表:
SELECT * FROM sys.time_zone_info
Run Code Online (Sandbox Code Playgroud)
是的,时区的命名很糟糕 - 即使是Eastern Standard Time
,也考虑了夏令时。
Aid*_*ela 44
我没有发现这些示例中的任何一个有助于将日期时间存储为UTC到指定时区的日期时间(不是服务器的时区,因为Azure SQL数据库以UTC身份运行).这就是我处理它的方式.它并不优雅,但它很简单,无需维护其他表格即可为您提供正确的答案:
select CONVERT(datetime, SWITCHOFFSET(dateTimeField, DATEPART(TZOFFSET,
dateTimeField AT TIME ZONE 'Eastern Standard Time')))
Run Code Online (Sandbox Code Playgroud)
Ron*_*ith 21
如果您需要服务器位置以外的转换,此功能允许您传递标准偏移量并记录美国夏令时:
-- =============================================
-- Author: Ron Smith
-- Create date: 2013-10-23
-- Description: Converts UTC to DST
-- based on passed Standard offset
-- =============================================
CREATE FUNCTION [dbo].[fn_UTC_to_DST]
(
@UTC datetime,
@StandardOffset int
)
RETURNS datetime
AS
BEGIN
declare
@DST datetime,
@SSM datetime, -- Second Sunday in March
@FSN datetime -- First Sunday in November
-- get DST Range
set @SSM = datename(year,@UTC) + '0314'
set @SSM = dateadd(hour,2,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
set @FSN = datename(year,@UTC) + '1107'
set @FSN = dateadd(second,-1,dateadd(hour,2,dateadd(day,datepart(dw,@FSN)*-1+1,@FSN)))
-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
set @StandardOffset = @StandardOffset + 1
-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)
-- return converted datetime
return @DST
END
GO
Run Code Online (Sandbox Code Playgroud)
好吧,如果您将数据作为 UTC 日期存储在数据库中,您可以执行以下简单操作
select
[MyUtcDate] + getdate() - getutcdate()
from [dbo].[mytable]
Run Code Online (Sandbox Code Playgroud)
从服务器的角度来看,它始终是本地的,并且您不会摸索 AT TIME ZONE 'your time zone name'
,如果您的数据库移动到另一个时区(例如客户端安装),则硬编码的时区可能会困扰您。
小智 6
如果在数据库上启用CLR是一个选项以及使用sql server的时区,它可以很容易地用.Net编写.
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlDateTime fn_GetLocalFromUTC(SqlDateTime UTC)
{
if (UTC.IsNull)
return UTC;
return new SqlDateTime(UTC.Value.ToLocalTime());
}
}
Run Code Online (Sandbox Code Playgroud)
UTC日期时间值进入,并且相对于服务器的本地日期时间值出现.空值返回null.
使用新的SQL Server 2016机会:
CREATE FUNCTION ToLocalTime(@dtUtc datetime, @timezoneId nvarchar(256))
RETURNS datetime
AS BEGIN
return @dtUtc AT TIME ZONE 'UTC' AT TIME ZONE @timezoneId
/* -- second way, faster
return SWITCHOFFSET(@dtUtc , DATENAME(tz, @dtUtc AT TIME ZONE @timezoneId))
*/
/* -- third way
declare @dtLocal datetimeoffset
set @dtLocal = @dtUtc AT TIME ZONE @timezoneId
return dateadd(minute, DATEPART (TZoffset, @dtLocal), @dtUtc)
*/
END
GO
Run Code Online (Sandbox Code Playgroud)
但clr程序的工作速度提高了5倍:' - (
注意一个TimeZone的Offset可以改为冬季或夏季.例如
select cast('2017-02-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'
select cast('2017-08-08 09:00:00.000' as datetime) AT TIME ZONE 'Eastern Standard Time'
Run Code Online (Sandbox Code Playgroud)
结果:
2017-02-08 09:00:00.000 -05:00
2017-08-08 09:00:00.000 -04:00
Run Code Online (Sandbox Code Playgroud)
您不能只添加常量偏移量.
这些都不适合我,但下面这个 100% 有效。希望这可以帮助其他像我一样尝试转换它的人。
CREATE FUNCTION [dbo].[fn_UTC_to_EST]
(
@UTC datetime,
@StandardOffset int
)
RETURNS datetime
AS
BEGIN
declare
@DST datetime,
@SSM datetime, -- Second Sunday in March
@FSN datetime -- First Sunday in November
-- get DST Range
set @SSM = DATEADD(dd,7 + (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 2,0))+'02:00:00'
set @FSN = DATEADD(dd, (6-(DATEDIFF(dd,0,DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0))%7)),DATEADD(mm,(YEAR(GETDATE())-1900) * 12 + 10,0)) +'02:00:00'
-- add an hour to @StandardOffset if @UTC is in DST range
if @UTC between @SSM and @FSN
set @StandardOffset = @StandardOffset + 1
-- convert to DST
set @DST = dateadd(hour,@StandardOffset,@UTC)
-- return converted datetime
return @DST
END
Run Code Online (Sandbox Code Playgroud)
小智 6
最简单的答案并不总是在底部,但这一次是,并且可以在上面的评论中隐藏的某个地方看到。
使用您自己的“AT TIME ZONE”来捕获列/数据字段的 TzOffset,而不是当前的 SYSDATETIME。
在下面的数据中,有 2 个查询,第一个查询是 2 月数据(DST 关闭,阿姆斯特丹冬季)+1 差异,第二个查询是阿姆斯特丹 4 月数据,所以+2 小时差异。
SELECT TOP 2
MONTH(receiveTimeUTC) AS MonthInWinterOrSpring,
receiveTimeUTC,
CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, receiveTimeUTC), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS LocalTimeWrongNoDST,
CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, receiveTimeUTC), DATENAME(TzOffset, receiveTimeUTC AT TIME ZONE 'Central European Standard Time' ))) AS LocalTimeWithDST
FROM
sensordetails
ORDER BY
id
SELECT TOP 2
MONTH(receiveTimeUTC) AS MonthInWinterOrSpring,
receiveTimeUTC,
CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, receiveTimeUTC), DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS LocalTimeWrongNoDST,
CONVERT(datetime, SWITCHOFFSET(CONVERT(datetimeoffset, receiveTimeUTC), DATENAME(TzOffset, receiveTimeUTC AT TIME ZONE 'Central European Standard Time' ))) AS LocalTimeWithDST
FROM
sensordetails
ORDER BY
id DESC
Run Code Online (Sandbox Code Playgroud)
结果:
所以这是一个 T-SQL(SQL Server 答案),不需要存储过程或函数。
没有简单的方法可以以正确和通用的方式做到这一点。
首先,必须了解偏移量取决于相关日期、时区和夏令时。
GetDate()-GetUTCDate
仅在服务器的 TZ 处为您提供今天的偏移量,这无关紧要。
我只看到了两个有效的解决方案,而且我搜索了很多。
1) 一个自定义 SQL 函数,带有几个基本数据表,例如每个 TZ 的时区和 DST 规则。工作但不是很优雅。我不能发布它,因为我没有代码。
编辑:这是此方法的示例 https://gist.github.com/drumsta/16b79cee6bc195cd89c8
2) 将 .net 程序集添加到数据库中,.Net 可以很容易地做到这一点。这工作得很好,但缺点是您需要在服务器级别配置多个参数,并且配置很容易被破坏,例如,如果您恢复数据库。我使用这种方法,但我不能发布它,因为我不拥有代码。
此功能将 UTC 时间转换为经过 DST 调整的 EST 时间。您可以在此函数中更改您设计的时区名称,或从注册表中获取它:
Create Function fnConvertUTCTimetoESTTime(
@UTCTime as datetime
)
returns datetime
as
begin
return convert(datetime, convert(varchar(23), @UTCTime AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time', 121), 121)
end
go
select dbo.fnConvertUTCTimetoESTTime ('2020-3-8 5:00:00.000')
, dbo.fnConvertUTCTimetoESTTime ('2020-3-8 6:00:00.000')
, dbo.fnConvertUTCTimetoESTTime ('2020-3-8 7:00:00.000')
, dbo.fnConvertUTCTimetoESTTime ('2020-3-8 8:00:00.000')
--returns 0:00am, 1:00am, 3:00am, 4:00am
select dbo.fnConvertUTCTimetoESTTime ('2020-11-1 4:00:00.000')
, dbo.fnConvertUTCTimetoESTTime ('2020-11-1 5:00:00.000')
, dbo.fnConvertUTCTimetoESTTime ('2020-11-1 6:00:00.000')
, dbo.fnConvertUTCTimetoESTTime ('2020-11-1 7:00:00.000')
--returns 0:00am, 1:00am, 1:00am, 2:00am
Run Code Online (Sandbox Code Playgroud)
请注意,您不能只返回“@UTCTime AT TIME ZONE 'UTC' AT TIME ZONE 'Eastern Standard Time'”作为结果,因为此结果实际上是 EST 格式的 UTC 时间(当您比较此“假”EST 时间或包含它在订单子句中,它将被转换回 UTC 时间)。
归档时间: |
|
查看次数: |
376478 次 |
最近记录: |