如何使用psycopg2比较日期(PostgreSQL)?
我想用PostgreSQL的Python模块psycopg2来查找一些数据行,这些行的结束时间在某个时间戳之前。我尝试通过执行一个SQL查询来实现这个目标,查询中包含了… where end_time < %s
,这里的%s是一个带时区的datetime.datetime
对象。psycopg2生成的SQL语句是:
select * from my_table where end_time < '2014-05-01T13:00:00+00:00'::timestamptz;
这个查询返回了一行数据,内容是:
id | start_time | end_time
331 | 2014-05-01 14:55:00 | 2014-05-01 15:05:00
但是结束时间并没有早于2014年5月1日13:00 UTC,这和我预期的结果不一样。
那么,在psycopg2中,正确的时间选择方式应该是什么呢?
2 个回答
指定时间应该以哪个时区来显示。如果start_time
和end_time
是没有时区的时间戳,正如你的输出所示,那么你还需要告诉PostgreSQL应该使用哪个时区来处理这些时间。
select
id,
start_time at time zone 'UTC' at time zone 'UTC',
end_time at time zone 'UTC' at time zone 'UTC'
from my_table
where end_time at time zone 'UTC' < %s
好的,使用带时区的PostgreSQL时间戳解决了问题。
下面是问题的详细情况:
我把带时区的时间戳放在了不带时区的列里。我以为
timestamp without time zone
列会存储UTC时间(就像timestamp with time zone
一样),但实际上它存的是本地时间的时间戳,正如文档中所描述的:在没有时区的时间戳和带时区的时间戳之间进行转换时,通常假设没有时区的时间戳值应该被视为本地时间。如果需要转换,可以使用AT TIME ZONE指定不同的时区。
因此,在中国,00:00 UTC会被存储为
08:00
在timestamp without time zone
这一列中。当进行比较时,比如“没有时区的时间戳”<“带时区的时间戳”,我在文档中找不到PostgreSQL是怎么处理的。不过,问题中观察到的情况和这样的想法是一致的:首先去掉时区,然后比较没有时区的时间戳。我不应该对结果感到惊讶:在中国,晚上的“15:00”确实是比13:00 UTC要早的(中国是UTC+8)。关键是要知道显示(和存储)的时间是本地时区的。
我从中得到的教训是:在带时区和不带时区的时间戳之间的转换最好是明确处理。