按当地时间查询事件

时间:2011-09-26 17:25:13

标签: sql sql-server-2005 timezone dst

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

我考虑过维护一个包含所有timezone / dst规则的表格。然后我可以将我的事件表加入到该表中,将结果限制为用户的timezone / 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. 使用临时表为每个区域建立每个区域的时间范围。

2 个答案:

答案 0 :(得分:0)

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

不是在查询期间转换表格中的数据,而是可以反转逻辑,而是将用户的本地时间范围参数转换为GMT,然后在GMT中执行所有操作。如果您希望返回当地时间的结果,则可以在此时再次转换。

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

答案 1 :(得分:0)

在这种情况下,如果我们从前面调用此过程,我们通常会传入当前的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