Postgres时间与时区比较
Postgres time comparaison with time zone
今天遇到一个奇怪的postgres行为。让我解释一下:
这是我的 table 我会继续努力。
=># \d planning_time_slot
Table "public.planning_time_slot"
Column | Type | Collation | Nullable | Default
-------------+---------------------------+-----------+----------+------------------------------------------------
id | integer | | not null | nextval('planning_time_slot_id_seq'::regclass)
planning_id | integer | | not null |
day | character varying(255) | | not null |
start_time | time(0) without time zone | | not null |
end_time | time(0) without time zone | | not null |
day_id | integer | | not null | 0
Indexes:
"planning_time_slot_pkey" PRIMARY KEY, btree (id)
"idx_a9e3f3493d865311" btree (planning_id)
Foreign-key constraints:
"fk_a9e3f3493d865311" FOREIGN KEY (planning_id) REFERENCES planning(id)
我想做的是:
select * from planning_time_slot where start_time > (CURRENT_TIME AT TIME ZONE 'Europe/Paris');
但 postgres 似乎在比较时区转换之前的时间。
这是我的测试:
=># select * from planning_time_slot where start_time > (CURRENT_TIME AT TIME ZONE 'Europe/Paris');
id | planning_id | day | start_time | end_time | day_id
-----+-------------+-----+------------+----------+--------
157 | 6 | su | 16:00:00 | 16:30:00 | 0
(1 row)
=># select (CURRENT_TIME AT TIME ZONE 'Europe/Paris');
timezone
--------------------
16:35:48.591002+02
(1 row)
当我尝试输入大量条目时,似乎在 start_time 和 CURRENT_TIME 之间进行了比较,但没有转换时区。
为了您的信息,我也试过了:
select * from planning_time_slot where start_time > timezone('Europe/Paris', CURRENT_TIME);
它有完全相同的结果。
我还尝试将列类型更改为 time(0) with time zone。它产生完全相同的结果。
最后一点很重要。我真的需要设置我想要的时区,因为稍后我会根据其他内容动态更改它。所以不会每次都是'Europe/Paris'。
有人有线索或提示吗?
psql (PostgreSQL) 11.2 (Debian 11.2-1.pgdg90+1)
我认为你有更深层次的问题。
您有一天、开始时间和结束时间,但没有时区的概念。因此,这将根据观察者的时区而有所不同。
我认为你应该添加一个 tz
列来存储信息所在的时区。然后你可以这样获取开始时间:
WHERE (day + start_time) AT TIME ZONE tz > current_timestamp
例如,(CURRENT_TIME AT TIME ZONE 'Europe/Paris')
就是 17:52:17.872082+02
。但在内部它是 15:52:17.872082+00
。 time 和 timetz(带时区的时间)都存储为 UTC,唯一的区别是 timetz 存储 时区 。更改时区不会更改它所代表的时间点。
所以当你将它与时间进行比较时...
# select '17:00:00'::time < '17:52:17+02'::timetz;
?column?
----------
f
那真是...
# select '17:00:00'::time < '15:52:17'::time;
?column?
----------
f
将 timetz 转换为 time 会去掉时区。
test=# select (CURRENT_TIME AT TIME ZONE 'Europe/Paris')::time;
timezone
-----------------
17:55:57.099863
(1 row)
test=# select '17:00:00' < (CURRENT_TIME AT TIME ZONE 'Europe/Paris')::time;
?column?
----------
t
请注意,只有当您想根据墙上的时钟存储某件事发生在 17:00 的概念时,这种比较才有意义。例如,如果您有一个移动 phone 游戏,其中事件“在 17:00”开始,这意味着 17:00 用户所在的位置。这被称为“浮动时区”。
- 假设
day
是“星期几”,我建议将其存储为整数。比较和本地化更容易。
- 考虑单个
timerange
. Then you can use range operators. 而不是单独的开始和结束时间
今天遇到一个奇怪的postgres行为。让我解释一下:
这是我的 table 我会继续努力。
=># \d planning_time_slot
Table "public.planning_time_slot"
Column | Type | Collation | Nullable | Default
-------------+---------------------------+-----------+----------+------------------------------------------------
id | integer | | not null | nextval('planning_time_slot_id_seq'::regclass)
planning_id | integer | | not null |
day | character varying(255) | | not null |
start_time | time(0) without time zone | | not null |
end_time | time(0) without time zone | | not null |
day_id | integer | | not null | 0
Indexes:
"planning_time_slot_pkey" PRIMARY KEY, btree (id)
"idx_a9e3f3493d865311" btree (planning_id)
Foreign-key constraints:
"fk_a9e3f3493d865311" FOREIGN KEY (planning_id) REFERENCES planning(id)
我想做的是:
select * from planning_time_slot where start_time > (CURRENT_TIME AT TIME ZONE 'Europe/Paris');
但 postgres 似乎在比较时区转换之前的时间。 这是我的测试:
=># select * from planning_time_slot where start_time > (CURRENT_TIME AT TIME ZONE 'Europe/Paris');
id | planning_id | day | start_time | end_time | day_id
-----+-------------+-----+------------+----------+--------
157 | 6 | su | 16:00:00 | 16:30:00 | 0
(1 row)
=># select (CURRENT_TIME AT TIME ZONE 'Europe/Paris');
timezone
--------------------
16:35:48.591002+02
(1 row)
当我尝试输入大量条目时,似乎在 start_time 和 CURRENT_TIME 之间进行了比较,但没有转换时区。
为了您的信息,我也试过了:
select * from planning_time_slot where start_time > timezone('Europe/Paris', CURRENT_TIME);
它有完全相同的结果。
我还尝试将列类型更改为 time(0) with time zone。它产生完全相同的结果。
最后一点很重要。我真的需要设置我想要的时区,因为稍后我会根据其他内容动态更改它。所以不会每次都是'Europe/Paris'。
有人有线索或提示吗?
psql (PostgreSQL) 11.2 (Debian 11.2-1.pgdg90+1)
我认为你有更深层次的问题。
您有一天、开始时间和结束时间,但没有时区的概念。因此,这将根据观察者的时区而有所不同。
我认为你应该添加一个 tz
列来存储信息所在的时区。然后你可以这样获取开始时间:
WHERE (day + start_time) AT TIME ZONE tz > current_timestamp
(CURRENT_TIME AT TIME ZONE 'Europe/Paris')
就是 17:52:17.872082+02
。但在内部它是 15:52:17.872082+00
。 time 和 timetz(带时区的时间)都存储为 UTC,唯一的区别是 timetz 存储 时区 。更改时区不会更改它所代表的时间点。
所以当你将它与时间进行比较时...
# select '17:00:00'::time < '17:52:17+02'::timetz;
?column?
----------
f
那真是...
# select '17:00:00'::time < '15:52:17'::time;
?column?
----------
f
将 timetz 转换为 time 会去掉时区。
test=# select (CURRENT_TIME AT TIME ZONE 'Europe/Paris')::time;
timezone
-----------------
17:55:57.099863
(1 row)
test=# select '17:00:00' < (CURRENT_TIME AT TIME ZONE 'Europe/Paris')::time;
?column?
----------
t
请注意,只有当您想根据墙上的时钟存储某件事发生在 17:00 的概念时,这种比较才有意义。例如,如果您有一个移动 phone 游戏,其中事件“在 17:00”开始,这意味着 17:00 用户所在的位置。这被称为“浮动时区”。
- 假设
day
是“星期几”,我建议将其存储为整数。比较和本地化更容易。 - 考虑单个
timerange
. Then you can use range operators. 而不是单独的开始和结束时间