自 DST 日期以来获取行的正确方法?

Proper way of getting rows since a date accounting for DST?

我有一个日期时间列 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,这是否可以正确说明 DST 更改?根据我找到的文档,这是我的理解,但我不能 100% 确定它是否是这样工作的,或者我是否遗漏了什么。

首先,找出您要比较的时间:

-- 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 字段是 datetimedatetime2。如果是datetimeoffset,你应该先将目标值转换成同一时区的datetimeoffset,然后用它来代替:

DECLARE @sinceDTO datetimeoffset = @since AT TIME ZONE 'Eastern Standard Time'

关于你在问题中给出的方法,有两个问题:

  • getdate() 给出基于服务器本地时区的时间。东部时间可能不是同一天。

  • 永远不要对 where 子句中的 table 字段应用函数(无论是 AT TIME ZONE 之类的内部函数还是其他函数),因为它使查询 non-sargable。换句话说,SQL 必须扫描整个 table,而不是使用索引。 table 越大,查询速度越慢。