自 DST 日期起获取行的正确方法?
Posted
技术标签:
【中文标题】自 DST 日期起获取行的正确方法?【英文标题】:Proper way of getting rows since a date accounting for DST? 【发布时间】:2020-11-05 11:40:51 【问题描述】:我有一个日期时间列 changedate
,我需要使用它来获取自下午 1 点以来在上周发生更改的行。不幸的是,本专栏采用的是当地时间 (EST)。服务器是 Microsoft SQL Server 2016。
这是我现在的查询:
DECLARE @since datetime = DATEADD(week,-1,SMALLDATETIMEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()), 13, 0)) AT TIME ZONE 'Eastern Standard Time'
SELECT * FROM table WHERE changedate AT TIME ZONE 'Eastern Standard Time' >= @since
由于我对列和@since
都使用了AT TIME ZONE
,这是否能正确解释夏令时的变化?根据我找到的文档,这是我的理解,但我不能 100% 确定它是如何工作的,或者我是否遗漏了一些东西。
【问题讨论】:
【参考方案1】:首先,确定您要比较的时间:
-- Get the current date in the given time zone
DECLARE @today date = convert(date, sysdatetimeoffset() AT TIME ZONE 'Eastern Standard Time')
-- Get the date one week ago
DECLARE @dateOneWeekAgo date = DATEADD(week, -1, @today)
-- Join the date with the desired time (local to the same time zone)
DECLARE @since datetime = convert(datetime, @dateOneWeekAgo) + convert(datetime, timefromparts(1, 0, 0, 0, 0))
那就对比一下吧:
SELECT * FROM table WHERE changedate >= @since
假设您的changedate
字段是datetime
或datetime2
。如果是datetimeoffset
,则应先将目标值转换为同一时区的datetimeoffset
,然后改用:
DECLARE @sinceDTO datetimeoffset = @since AT TIME ZONE 'Eastern Standard Time'
关于你在问题中给出的方法,有两个问题:
getdate()
给出基于服务器本地时区的时间。东部时间可能不是同一天。
你不应该对 where 子句中的表字段应用函数(无论是像 AT TIME ZONE
这样的内部函数还是其他函数),因为它会生成查询 non-sargable。换句话说,SQL 必须扫描整个表,而不是使用索引。表越大,查询速度越慢。
【讨论】:
哇,非常感谢,也感谢您的提示(显示我缺乏 SQL 知识)!因此,如果我理解正确,按照您的描述声明@since
并将其用作 changedate
的标准(在 EDT 或 EST 中是 datetime
)将正确解释该字段中的任何 DST 更改?
假设该字段中的数据确实是在美国和加拿大观察到的东部时间 - 即冬季的 EST (UTC-5),夏季的 EDT (UTC-4) - 然后 是的。但是,如果由于某种原因,该字段中的数据实际上是 UTC-5,则将第一行更改为:DECLARE @today date = convert(date, switchoffset(sysdatetimeoffset(), '-05:00'))
。见the switchoffset
docs。以上是关于自 DST 日期起获取行的正确方法?的主要内容,如果未能解决你的问题,请参考以下文章