给定一个名为的表bananas
和一个名为的timestamp without time zone
列end_time
, 一些 psql
客户端有set timezone to 'UTC'
, 其他 psql
客户端有set timezone to 'US/Eastern'
,服务器配置timezone = 'UTC'
在postgresql.conf
如何编写检查约束bananas.end_time
以确保end_time
始终是一天的结束,定义为“美国/东部”一天的第 23 小时、第 59 分钟和第 59 秒?
我试过了:
alter table bananas
add constraint ck_end_time_is_end_of_day
check (
23 = date_part('hour', end_time at time zone 'UTC' at time zone 'US/Eastern')
and 59 = date_part('minute', end_time at time zone 'UTC' at time zone 'US/Eastern')
and 59 = floor(date_part('second', end_time at time zone 'UTC' at time zone 'US/Eastern'))
)
;
这似乎正确地限制了列,但它似乎效率低得可怕,而且非常不可读。是否有更高效和/或更易读的实现?
目前
虽然坚持你不幸的解决方案:
没错,
AT TIME ZONE
两次:第一个实例将您
timestamp without time zone
转换为timestamp with time zone
. 这是假设您实际上是在存储 UTC 时间。第二个实例将
timestamptz
back转换timestamp
为您给定的 time zone。现在您可以检查该time
组件是否符合您的要求。Cast to
time
,而不是转换为字符串,这更便宜且更健壮。要摆脱小数位,您可以
time(0)
改为转换为,但在您的示例中,这会舍入值而不是下限。相反,用 截断date_trunc()
,这是floor()
使用正数的更便宜的方法:适当的解决方案
timestamp
值有小数位,使用时间分量'23:59:59'
作为上限是一个不幸的决定。取而代之的是,使用00:00
第二天作为排他的上边界。使用检查约束来强制执行它是微不足道的。接下来,由于您要处理多个时区,我建议使用
timestamptz
而不是timestamp
.timestamp
内部存储与给定时区“UTC”中的存储相同,但输入/输出处理不同。关于 SO 的相关答案有更多细节。
您可以使用
to_char
从单个函数调用中获取时间字段:给出的秒数
SS
没有四舍五入,因此应该可以等同于floor
尝试这个。它可能更快,但仍然不可读: