启用时区的星期查询

时间:2018-02-08 03:53:05

标签: django postgresql timestamp-with-timezone

考虑一个简单的DB Schema:

Table XYZ:
    filter_datetime: DateTime field (With Timezone enabled)

现在,如果我想找到filter_datetime在"星期一"上发生的所有XYZ行,如果我忽略时区则可以这样做。

但是,如果我不想忽略时区信息,如何查询?

另外,特别针对我的情况,我可以确保filter_datetime具有相同的时区。但是,一旦填充了表,用户应该能够根据不同的时区进行查询并获得正确的结果。 (那是UTC + 6:00的用户在尝试获取星期一行时会有不同的行,而不是在UTC-6:00中有时区的用户)

奖金(我真的不需要接受答案):是否有可能通过Django ORM?

1 个答案:

答案 0 :(得分:0)

样品:

t=# create table xyz(filter_datetime timestamptz);
CREATE TABLE
t=# insert into xyz select generate_series('2018-02-04'::timestamptz,'2018-02-14'::timestamptz,'4 hour'::interval);
INSERT 0 61

选择(如果你不想忽视TZ - 只是不要忽视它):

t=# set TimeZone to 'UTC-6:00';
SET
t=# select ctid,filter_datetime at time zone 'UTC' utc, filter_datetime,to_char(filter_datetime,'Day'), extract(dow from filter_datetime)
from xyz
where extract(dow from filter_datetime) = 1
order by 1;
  ctid  |         utc         |    filter_datetime     |  to_char  | date_part
--------+---------------------+------------------------+-----------+-----------
 (0,6)  | 2018-02-04 20:00:00 | 2018-02-05 02:00:00+06 | Monday    |         1
 (0,7)  | 2018-02-05 00:00:00 | 2018-02-05 06:00:00+06 | Monday    |         1
 (0,8)  | 2018-02-05 04:00:00 | 2018-02-05 10:00:00+06 | Monday    |         1
 (0,9)  | 2018-02-05 08:00:00 | 2018-02-05 14:00:00+06 | Monday    |         1
 (0,10) | 2018-02-05 12:00:00 | 2018-02-05 18:00:00+06 | Monday    |         1
 (0,11) | 2018-02-05 16:00:00 | 2018-02-05 22:00:00+06 | Monday    |         1
 (0,48) | 2018-02-11 20:00:00 | 2018-02-12 02:00:00+06 | Monday    |         1
 (0,49) | 2018-02-12 00:00:00 | 2018-02-12 06:00:00+06 | Monday    |         1
 (0,50) | 2018-02-12 04:00:00 | 2018-02-12 10:00:00+06 | Monday    |         1
 (0,51) | 2018-02-12 08:00:00 | 2018-02-12 14:00:00+06 | Monday    |         1
 (0,52) | 2018-02-12 12:00:00 | 2018-02-12 18:00:00+06 | Monday    |         1
 (0,53) | 2018-02-12 16:00:00 | 2018-02-12 22:00:00+06 | Monday    |         1
(12 rows)

t=# set TimeZone to 'UTC+6:00';
SET
t=# select ctid,filter_datetime at time zone 'UTC' utc, filter_datetime,to_char(filter_datetime,'Day'), extract(dow from filter_datetime)
from xyz
where extract(dow from filter_datetime) = 1
order by 1;
  ctid  |         utc         |    filter_datetime     |  to_char  | date_part
--------+---------------------+------------------------+-----------+-----------
 (0,9)  | 2018-02-05 08:00:00 | 2018-02-05 02:00:00-06 | Monday    |         1
 (0,10) | 2018-02-05 12:00:00 | 2018-02-05 06:00:00-06 | Monday    |         1
 (0,11) | 2018-02-05 16:00:00 | 2018-02-05 10:00:00-06 | Monday    |         1
 (0,12) | 2018-02-05 20:00:00 | 2018-02-05 14:00:00-06 | Monday    |         1
 (0,13) | 2018-02-06 00:00:00 | 2018-02-05 18:00:00-06 | Monday    |         1
 (0,14) | 2018-02-06 04:00:00 | 2018-02-05 22:00:00-06 | Monday    |         1
 (0,51) | 2018-02-12 08:00:00 | 2018-02-12 02:00:00-06 | Monday    |         1
 (0,52) | 2018-02-12 12:00:00 | 2018-02-12 06:00:00-06 | Monday    |         1
 (0,53) | 2018-02-12 16:00:00 | 2018-02-12 10:00:00-06 | Monday    |         1
 (0,54) | 2018-02-12 20:00:00 | 2018-02-12 14:00:00-06 | Monday    |         1
 (0,55) | 2018-02-13 00:00:00 | 2018-02-12 18:00:00-06 | Monday    |         1
 (0,56) | 2018-02-13 04:00:00 | 2018-02-12 22:00:00-06 | Monday    |         1
(12 rows)

如您所见,具有不同TimeZone的客户端会将不同的行视为星期一。这是因为timestamptz将时间保留在UTC中 - 而不是在客户端时区。返回客户端时转换它。

https://www.postgresql.org/docs/current/static/datatype-datetime.html

  

对于带时区的时间戳,内部存储的值始终为   UTC(通用协调时间,传统上称为格林威治标准   时间,GMT)。具有指定显式时区的输入值是   使用该时区的适当偏移量转换为UTC。如果   在输入字符串中没有声明时区,则假定它是   在系统的TimeZone参数指示的时区中,是   使用时区的偏移量转换为UTC。

https://www.postgresql.org/docs/current/static/functions-formatting.html