我正在做一些SQL选择查询,并希望将我的UTC日期时间列转换为本地时间,以便在我的查询结果中显示为本地时间。注意,我不希望通过代码进行这种转换,而是当我对我的数据库进行手动和随机SQL查询时。
当前回答
没有一种简单的方法能以正确而通用的方式做到这一点。
首先,必须理解偏移量取决于所讨论的日期、时区和夏令时。 GetDate()-GetUTCDate只提供今天服务器TZ的偏移量,这是不相关的。
我只见过两种有效的解决方案,我已经搜索了很多。
1)一个自定义SQL函数,包含几个基本数据表,如每个TZ的时区和夏令时规则。 工作,但不是很优雅。我不能发布,因为我没有代码。
编辑:下面是这个方法的一个例子 https://gist.github.com/drumsta/16b79cee6bc195cd89c8
2)添加一个.net程序集到db, .net可以很容易地做到这一点。这工作得很好,但缺点是你需要在服务器级配置几个参数,配置很容易被破坏,例如,如果你恢复数据库。 我使用这个方法,但我不能张贴它,因为我没有自己的代码。
其他回答
我发现当有大量数据时,一次性函数的方法太慢了。因此,我通过连接到一个允许计算小时差的表函数来实现它,它基本上是带有小时偏移量的datetime分段。一年是4行。这个表格函数
dbo.fn_getTimeZoneOffsets('3/1/2007 7:00am', '11/5/2007 9:00am', 'EPT')
将返回这个表:
startTime endTime offset isHr2
3/1/07 7:00 3/11/07 6:59 -5 0
3/11/07 7:00 11/4/07 6:59 -4 0
11/4/07 7:00 11/4/07 7:59 -5 1
11/4/07 8:00 11/5/07 9:00 -5 0
它确实考虑了夏时制。下面是它如何使用的示例,完整的博客文章在这里。
select mt.startTime as startUTC,
dateadd(hh, tzStart.offset, mt.startTime) as startLocal,
tzStart.isHr2
from MyTable mt
inner join dbo.fn_getTimeZoneOffsets(@startViewUTC, @endViewUTC, @timeZone) tzStart
on mt.startTime between tzStart.startTime and tzStart.endTime
这样就可以获得与夏令时同步的服务器时间
declare @dt datetime
set @dt = getutcdate() -- GMT equivalent
sysdatetimeoffset会考虑夏令时
select [InputTime] = @dt
, [LocalTime2] = dateadd(mi, datediff(mi, sysdatetimeoffset(),getdate()), @dt)
我使用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
罗恩的回答有一个错误。它使用当地时间凌晨2:00,其中需要UTC等效值。我没有足够的声望分数来评论Ron的回答,所以更正版本如下:
-- =============================================
-- 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 - @StandardOffset,dateadd(day,datepart(dw,@SSM)*-1+1,@SSM))
set @FSN = datename(year,@UTC) + '1107'
set @FSN = dateadd(second,-1,dateadd(hour,2 - (@StandardOffset + 1),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
UNIX时间戳只是一个特定日期和UNIX纪元之间的秒数,
SELECT DATEDIFF(SECOND,{d '1970-01-01'},GETDATE()) //返回SQL server中的UNIX时间戳
你可以创建一个函数,使用Country Offset将本地日期时间转换为Unix UTC SQL server中的Unix时间戳函数
推荐文章
- 如何在Ruby On Rails中使用NuoDB手动执行SQL命令
- 查询JSON类型内的数组元素
- 确定记录是否存在的最快方法
- 获得PostgreSQL数据库中当前连接数的正确查询
- 在SQL选择语句Order By 1的目的是什么?
- 从现有模式生成表关系图(SQL Server)
- 我如何循环通过一组记录在SQL Server?
- 数据库和模式的区别
- 如何在SQL Server中一次更改多个列
- 如何从命令行通过mysql运行一个查询?
- 外键约束可能导致循环或多条级联路径?
- 使用LIMIT/OFFSET运行查询,还可以获得总行数
- 当恢复sql时,psql无效命令\N
- 货币应该使用哪种数据类型?
- 如何选择每一行的列值不是独特的