2016-12-27 82 views
0

我确定标题可能会令人困惑。无法找到一种方法来在标题中很好地说出这一点,而不会使其长度为非常长无论夏令时如何,只在UTC 2:00检索时间戳(带时区)行的SQL查询

在短期

我有存档外部API端点每15分钟一个PSQL数据库表。该表具有以下的列:

  • ID(串行)
  • 比赛(jsonb)
  • snapshot_time(时间戳和时区不为空默认NOW())

我需要一个SQL只能在以下约束下获取行的查询:

  • 一天必须星期六(6)
  • 时间戳必须在'... T02:00:00Z'ISO8601
  • 在指定的开始和结束日期之间。

我现在有

SELECT id,snapshot_time,match->'kills' FROM match_archive 
WHERE extract(dow from snapshot_time)=6 
AND snapshot_time >= '2016-12-01' 
AND date_part('hour', snapshot_time)=2 
AND date_part('minute', snapshot_time)=00; 

(开始&结束时间,目前很难在例如编码)

的问题

这将返回正确的行,但问题是自snapshot_time列以来的结果行是因为我住在东部标准时间,所以timestamp with time zone型实际上是5个小时。

它返回一个例子行

id |   snapshot_time   |     ?column? 
--------+-------------------------------+-------------------------------------------- 
120941 | 2016-12-03 02:00:03.32946-05 | {"red": 3389, "blue": 1962, "green": 2911} 

正如你所看到的,snapshot_time确实是2:00,但它在美国东部时间。

我想,“嘿,我可以让它的小时:21,星期几:5(星期五)”,这样就行得通了,但突然间由于夏令时将在一个小时后关闭。

其他的事情将使用timestamp without time zone来存储信息,但会发生什么,然后是它会采取2016-12-03T17:44:21-05,只是砍掉-05并把它作为2016-12-03T17:44:21Z插入新行到数据库时。

那么,有没有什么好方法可以让SQL查询符合上面列出的要求而不必担心夏令时?谢谢。

+0

虽然我意识到您可能没有这个选项,但理解最佳做法是始终将UTC中的日期时间数据存储在首位。如果这样做了,这个问题就不会出现。即使是现在,如果我有选择,我会认真研究将数据库中的所有现有本地时区日期时间数据(以及从其驱动的代码)转换为UTC。 –

+0

@CharlesBretana存储UTC时区甚至不是PostgreSQL中的选择。这就是它们的存储方式。 –

+0

我没说店时区,我说在UTC存储日期倍。然而,我承认我不熟悉PostgreSQL。你是说你无法控制你存储在PostGreSQL表的日期时间列中的值吗?客户端软件无法存储UTC值而不是本地时间值? –

回答

2

这将返回正确的行,但问题是自snapshot_time列以来的结果行是时区类型的时间戳实际上是5个小时,因为我住在东部标准时间。

时间戳总是存储在PostgreSQL的UTC,per the docs

对于带有时区的时间标记,内部存储的数值总是UTC(全球统一时间,习惯上称为格林威治标准时间(GMT)) 。使用该时区的适当偏移量将具有指定明确时区的输入值转换为UTC。如果没有时间段被输入字符串表示,那么它被认为是在由该系统的时区参数所表示的时间带,并使用被转换为UTC的时区区域中的偏移量。

当与时区值的时间戳输出,它总是从UTC转换成当前时区区域,并且如在该区域的本地时间显示。要查看另一个时区的时间,可以更改时区,要么使用AT TIME ZONE构造(见Section 9.9.3)。

0

回答我的情况下,任何人的问题遇到在谷歌这个问题。

继埃文·卡罗尔的答案,下面的SQL固定我的问题:

SELECT id,snapshot_time,match->'kills' FROM match_archive 
WHERE extract(dow from snapshot_time AT TIME ZONE 'UTC')=5 
AND snapshot_time >= '2016-12-01' 
AND date_part('hour', snapshot_time AT TIME ZONE 'UTC')=2 
AND date_part('minute', snapshot_time AT TIME ZONE 'UTC')=00; 

可能的微小date_part数没有必要,但要保持一致。

+0

或者,如果您希望UTC的时间,只需将客户端,数据库或操作系统中的本地时区设置为UTC即可。 –