使用AT TIME ZONE获取指定时区的当前时间

时间:2016-04-04 02:31:29

标签: sql-server timezone

我正在尝试在SQL Server 2016和Azure SQL中使用新的AT TIME ZONE syntax。我只想把伦敦的当前时间调整为datetime,并根据夏令时进行调整。在运行以下所有命令时,伦敦的时间是凌晨3点半。

第一步是获得datetimeoffset,我可以按照以下方式成功完成:

DECLARE @dto datetimeoffset
SET @dto = (SELECT GETUTCDATE() AT TIME ZONE 'GMT Standard Time')
SELECT @dto

这会返回一个我期望的值:

2016-04-04 02:27:54.0200000 +01:00

接下来,我想将其转换为datetime,这是我的应用程序所期望的。我尝试过三种不同的方法,但没有一种方法可以让我得到我想要的结果:

SELECT SWITCHOFFSET(@dto,'+00:00')
-- Returns 2016-04-04 01:27:54.0200000 +00:00

SELECT CONVERT(datetime, @dto)
-- Returns 2016-04-04 02:27:54.020

SELECT CONVERT(datetime2, @dto)
-- Returns 2016-04-04 02:27:54.0200000

我觉得我错过了一些明显的东西 - 是否有一种简单的方法可以获取datetimeoffset并仅返回该偏移处的日期/时间部分?

3 个答案:

答案 0 :(得分:22)

代码的第一行包含错误:

SELECT GETUTCDATE() AT TIME ZONE 'GMT Standard Time'

GETUTCDATE()返回datetime,其中没有时区偏移信息。因此,如the MSDN documentation

中所述
  

如果提供 inputdate 而没有偏移信息,则该函数会应用时区的偏移量,假设在目标时区中提供了 inputdate 值。

因此,即使您检索了UTC时间,您也错误地断言该值是在伦敦时间(在此日期夏令时为UTC + 1)。

处理此问题的最简单方法是将UTC时间作为datetimeoffset开始。

SELECT SYSDATETIMEOFFSET() AT TIME ZONE 'GMT Standard Time'

这会调用AT TIME ZONE转换功能,该文档在文档中说明:

  

如果 inputdate 作为 datetimeoffset 值提供,则AT TIME ZONE子句会使用时区转换规则将其转换为目标时区。

请注意,如果您的数据实际上来自某个地方的datetime字段,则可能需要使用两个部分功能,如下所示:

SELECT mydatetimefield AT TIME ZONE 'UTC' AT TIME ZONE 'GMT Standard Time'

AT TIME ZONE的第一次调用断言该值为UTC,给第二次调用datetimeoffset,将其转换为伦敦时间。

其中任何一项的输出均为datetimeoffset,您可以将其转换为datetimedatetime2,与您在原始问题中的显示完全相同。 (请勿使用switchoffset。)

此外,伦敦的Windows时区标识符始终为"GMT Standard Time"。它包括格林威治标准时间和英国夏令时,它们之间有适当的过渡。不要尝试将其更改为"GMT Daylight Time" - 该标识符不存在。有关Windows时区的部分the timezone tag wiki中也介绍了这一点。

答案 1 :(得分:1)

我建议您仅将此字符串存储为字符串,并确认它是本地时间表示形式,否则,如果服务器时间正确,则SQL Server内部存储的时间将是错误的实际/物理时间,但不是同一时区。这就是为什么您不能使用convert来表示相同的原因,因为您实际上是从实际发生的时间更改datetime值,而不仅仅是重新表示它,即Datetime始终存储为UTC,而是在服务器的时区中输入和显示,因此,如果您在datetime字段中输入本地时间,则服务器会将时间解释为服务器时区中的时间,而不是事件的实际时间,如果本地时间不是当前时间,则会导致存储的时间导航/偏差与服务器相同>如果您随后将相同的数据馈送到其他时区的其他系统,则它们的数据将不正确,并且可能会变得混乱。将正确的值存储在datetime字段中,并根据需要将其显示为字符串。

答案 2 :(得分:0)

由于我无法在其他我想分享的地方找到它。通过在AT TIME ZONE中使用datepart(tz),可以获取以分钟为单位的偏移量。

datepart(tz,UTC_Date AT TIME ZONE 'Central Standard Time')

select dateadd(MINUTE,datepart(tz,cast('2018-07-02 17:54:41.537' as datetime) AT Time Zone 'Central Standard Time'),'2018-07-02 17:54:41.537') as CentralTime

返回

CentralTime
2018-07-02 12:54:41.537