我正在尝试在SQL Server 2016和Azure SQL中使用新的AT TIME ZONE语法。我只是想把伦敦的当前时间作为datetime
,根据夏令时进行调整。在运行下面所有命令时,伦敦的时间是凌晨3点27分。
第一步是得到一个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
并只返回偏移处的日期/时间部分?
代码的第一行包含错误:
SELECT GETUTCDATE() AT TIME ZONE 'GMT Standard Time'
GETUTCDATE()
返回一个没有时区偏移信息的datetime
。如MSDN文档中所述:
如果提供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
,您可以将其强制转换或转换为datetime
或datetime2
,就像您在原始问题中显示的那样。(不要使用switchoffset
。)
此外,伦敦的Windows时区标识符始终为"GMT Standard Time"
。它包括格林尼治标准时间和英国夏令时,两者之间有适当的转换。不要尝试将其更改为"GMT Daylight Time"
-该标识符不存在。时区标签wiki中关于Windows时区的部分也介绍了这一点。
由于我在其他任何地方都找不到这个,我想我可以分享。您可以通过将datepart(tz)与AT TIME ZONE一起使用来获得以分钟为单位的偏移量。
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
我建议您只将其存储为字符串,并限定它是本地时间表示,否则,如果服务器时间正确,但不在同一时区,SQL Server内部存储的时间将是错误的实际/物理时间。这就是为什么您不能使用convert来表示相同的值,因为您实际上是在从实际发生的时间更改日期时间值,而不仅仅是重新表示它,即日期时间始终存储为UTC,而是在服务器的时区中输入和显示,所以如果您在日期时间字段中输入本地时间,服务器将该时间解释为服务器时区中的时间,而不是事件的实际时间,如果本地时间与服务器不同,则会导致存储的时间导航/偏差>如果您随后将相同的数据提供给不同时区的其他系统,它们将有不正确的数据,并且可能会变得混乱。将正确的值存储在datetime字段中,并根据需要将其显示为字符串。