Jar*_*eck 4 postgresql constraint datatypes timestamp timezone
考虑到一个指定的表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'))
)
;
Run Code Online (Sandbox Code Playgroud)
这似乎正确地限制了该列,但它似乎效率极低,而且非常不可读。是否有更高效和/或更易读的实现?
虽然坚持你不幸的解决方案:
CHECK ((end_time AT TIME ZONE 'UTC' AT TIME ZONE 'US/Eastern')::time = '23:59:59'::time)
Run Code Online (Sandbox Code Playgroud)
没错,AT TIME ZONE
两次:
一审将您timestamp without time zone
进入timestamp with time zone
。那是假设您实际上是在存储 UTC 时间。
第二个实例将timestamptz
返回转换timestamp
为您给定的时区。现在您可以检查time
组件是否是您想要的。
time
转换为,而不是转换为字符串,这更便宜且更健壮。
要摆脱小数位数,您可以time(0)
改为使用,但在您的示例中,它会舍入值而不是下限。相反,用 截断date_trunc()
,这是floor()
使用正数的更便宜的方法:
CHECK ((date_trunc('sec', end_time) AT TIME ZONE 'UTC' AT TIME ZONE 'US/Eastern')::time
= '23:59:59'::time)
Run Code Online (Sandbox Code Playgroud)
timestamp
值具有小数位数,使用时间分量'23:59:59'
作为上限是一个不幸的决定。取而代之的是,使用00:00
第二天作为独家上边界。这是微不足道的执行是一个检查约束。
接下来,因为你正在处理多个时区,我会建议使用timestamptz
的替代timestamp
。内部存储与timestamp
给定时区“UTC”中的相同,但输入/输出处理不同。
归档时间: |
|
查看次数: |
3329 次 |
最近记录: |