指定bananas
という名前のテーブル
およびtimestamp without time zone
という名前のend_time
列
およびsomepsql
クライアントはset timezone to 'UTC'
およびその他psql
クライアントはset timezone to 'US/Eastern'
andサーバー構成にはtimezone = 'UTC'
にpostgresql.conf
があります
bananas.end_time
にチェック制約を記述して、end_time
が常に1日の終わりになるようにするには、"US/Easternの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'))
)
;
これは列を正しく制限しているように見えますが、恐ろしく非効率的であり、まったく読めないようです。より効率的で読みやすい実装はありますか?
あなたの不幸な解決策で立ち往生している間:
_CHECK ((end_time AT TIME ZONE 'UTC' AT TIME ZONE 'US/Eastern')::time = '23:59:59'::time)
_
そうです、_AT TIME ZONE
_ two回:
最初のインスタンスは_timestamp without time zone
_を_timestamp with time zone
_に変換します。これは、実際にUTC時間を格納していることを前提としています。
2番目のインスタンスは、timestamptz
をtimestamp
に変換し直します指定されたタイムゾーンで。これで、time
コンポーネントが希望どおりであることを確認できます。
文字列に変換する代わりに、time
にキャストすると、より安価で堅牢になります。
小数桁を取り除くには、代わりにtime(0)
にキャストしますが、roundではなくfloorあなたの例では。代わりに、 date_trunc()
で切り捨てます。これは、正の数のfloor()
の安価な方法です。
_CHECK ((date_trunc('sec', end_time) AT TIME ZONE 'UTC' AT TIME ZONE 'US/Eastern')::time
= '23:59:59'::time)
_
timestamp
の値は小数桁であり、時間コンポーネント_'23:59:59'
_の使用は上限が不幸な決定であるためです。代わりに、次の日の_00:00
_を排他的な上限として使用を使用します。 thatをチェック制約で強制するのは簡単です。
次に、複数のタイムゾーンを扱っているので、timestamptz
の代わりに timestamp
を使用することをお勧めします。内部ストレージは、指定されたタイムゾーン「UTC」のtimestamp
と同じですが、入出力の処理が異なります。
to_char
を使用して、単一の関数呼び出しから時間フィールドを取得できます。
check (to_char(end_time at time zone 'UTC' at time zone 'US/Eastern','HH24:MI:SS') = '23:59:59')
SS
で指定された秒は切り上げられないため、floor
と同等で問題ありません。
これを試して。おそらくもっと速いですが、それでも判読できません:
alter table bananas
add constraint ck_end_time_is_end_of_day
check (
(end_time at time zone 'UTC' at time zone 'US/Eastern')::timestamp::date + interval '23:59:59' =
date_trunc('second', end_time at time zone 'UTC' at time zone 'US/Eastern')
)
;