【问题标题】:Query for events by local time按当地时间查询事件
【发布时间】:2011-11-25 09:45:13
【问题描述】:

我有一个带有 GMT 时间戳事件的数据库(SQL Server 2005,但我认为我的问题更笼统)。出于多种原因,我需要能够根据用户的本地时间查询和汇总数据。例如,当地时间下午 5 点到 7 点之间发生了多少事件? DST 真的让我在这个上循环。

我考虑过尝试维护一个包含所有时区/夏令时规则的表格。然后我可以将我的事件表加入其中,将结果限制为用户的时区/dst 信息。所以我的例子的查询看起来像:

select count(e.ID)
from events e
  join dst d on e.timeGMT between d.startGMT and d.endGMT
where d.region=@userRegion
  and dbo.getTime(dateadd(ss, d.offsetSec, e.timeGMT)) between '17:00' and '19:00'

这个 dst 表似乎很可能成为维护的噩梦。那么,有人有更好的选择吗?

更新 好吧,我的问题似乎有些混乱,所以我将提供一些示例数据......

首先,请注意,DST 在美国当地时间 11 月 6 日(星期日)02:00 结束。

鉴于以下事件表

create table events(ID int, timeGMT datetime)

insert into events(ID, timeGMT)
select  1, '2011-11-04 20:00' union --16:00 EDT
select  2, '2011-11-04 20:15' union --16:15 EDT
select  3, '2011-11-04 20:30' union --16:30 EDT
select  4, '2011-11-04 20:45' union --16:45 EDT
select  5, '2011-11-04 21:00' union --17:00 EDT
select  6, '2011-11-04 21:15' union --17:15 EDT
select  7, '2011-11-04 21:30' union --17:30 EDT
select  8, '2011-11-04 21:45' union --17:45 EDT
select  9, '2011-11-04 22:00' union --18:00 EDT
select 10, '2011-11-04 22:15' union --18:15 EDT
select 11, '2011-11-04 22:30' union --18:30 EDT
select 12, '2011-11-04 22:45' union --18:45 EDT
select 13, '2011-11-04 23:00' union --19:00 EDT
select 14, '2011-11-06 20:00' union --15:00 EST
select 15, '2011-11-06 20:15' union --15:15 EST
select 16, '2011-11-06 20:30' union --15:30 EST
select 17, '2011-11-06 20:45' union --15:45 EST
select 18, '2011-11-06 21:00' union --16:00 EST
select 19, '2011-11-06 21:15' union --16:15 EST
select 20, '2011-11-06 21:30' union --16:30 EST
select 21, '2011-11-06 21:45' union --16:45 EST
select 22, '2011-11-06 22:00' union --17:00 EST
select 23, '2011-11-06 22:15' union --17:15 EST
select 24, '2011-11-06 22:30' union --17:30 EST
select 25, '2011-11-06 22:45' union --17:45 EST
select 26, '2011-11-06 23:00'       --18:00 EST

我正在寻找一种获得以下结果的好方法。假设本地开始时间为 17:00,本地结束时间为 18:00,本地时区为美国复活节。

 ID | timeGMT
----|------------------
  5 | 2011-11-04 21:00
  6 | 2011-11-04 21:15
  7 | 2011-11-04 21:30
  8 | 2011-11-04 21:45
  9 | 2011-11-04 22:00
 22 | 2011-11-06 22:00
 23 | 2011-11-06 22:15
 24 | 2011-11-06 22:30
 25 | 2011-11-06 22:45
 26 | 2011-11-06 23:00

我还希望这适用于任何真实的 DST 规则集和所有时区。包括真实数据集跨越数年的事实,因此有数次 DST 变化。

更新 2 我已经基本实现了我最初概述的解决方案,但我还创建了一些代码来大幅减少所需的维护操作。

  1. 我解析了 tz 数据库(又名 zoneinfo、IANA 时区或 Olson 数据库,可用 here),输出所有 GMT 偏移变化的列表,这些年我必须担心的所有区域。李>
  2. 将列表插入到临时表中。
  3. 使用临时表为每个区域针对其具有的每个 GMT 偏移量构建时间范围。

【问题讨论】:

    标签: sql sql-server-2005 timezone dst


    【解决方案1】:

    嗯,只是一个你可能想要考虑的小想法:

    除了在查询期间转换表中的数据之外,您还可以反转逻辑,而是将用户的本地时间范围参数转换为 GMT,然后在 GMT 中执行所有操作。如果您想要返回本地时间的结果,您可以在那时再次转换。

    这是否是一个有效的解决方案将取决于您查询的性质。

    【讨论】:

    • 虽然我总体上同意你的观点,但我认为你在这里错过了问题的症结所在。您如何处理多个 DST 班次?要求用户记住夏令时开始/结束的时间?
    【解决方案2】:

    在这种情况下,如果我们从前面调用这个过程,我们通常会传入当前的 GMT 时间,如果是 .net,我们使用 System.DateTime.UtcNow 然后比较数据,使用这种方法我们不会必须在sql server中进行日期时间转换。

    已编辑:

        declare @table table(eventName Varchar(50), [time] time)
        insert into @table(eventName, [time]) Values ('event 1', '03:30')
        insert into @table(eventName, [time]) Values ('event 1', '04:00')
        insert into @table(eventName, [time]) Values ('event 2', '04:20')
        insert into @table(eventName, [time]) Values ('event 3', '05:20')
        insert into @table(eventName, [time]) Values ('event 3', '07:20')
    
        select * from @table
    
        -- assuming ur local time is +1 GMT
        declare 
            @timeFromLocal time = '05:00',
            @timeToLocal time = '07:00',
            @timeFromGMT time,
            @timeToGMT time,
            @Offset int = -1
    
        /*I prefer doing the following conversion from the front end where the time reflects the users time zone*/
        set @timeFromGMT = DATEADD(Hour, @Offset, @timeFromLocal)
        set @timeToGMT = DATEADD(Hour, @Offset, @timeToLocal)
    
        select * from @table Where [time] between @timeFromGMT and @timeToGMT
    

    【讨论】:

    • 这仍然会错过在多个 DST 班次中查询本地时间的事件。
    • 在上述情况下,由于您需要当地时间下午 5 点和晚上 7 点之间的事件,我会将这些时间从前端转换为相应的 gmt 时间,然后将其传递给程序。所以在数据库中你只需要检查它是否在这些 gmt 时间之间
    • 我的第一条评论仍然有效。如果事件具有跨越一个或多个 DST 班次的完整日期时间值,则每个相应的 DST 班次都需要存在 GMT 调整。这不包括这种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 2017-11-18
    • 2012-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多