今日はまたミスの話をしようと思う。だって日付や時間を扱うのって、地雷原を歩くようなもんでさ、最初の一歩を踏み外すまでは大丈夫なんだけどね。
データ型の選び方のミス
ここが全てのトラブルの始まりだったりする。データ型を間違えて選ぶと、日付や時間の扱いが全部台無しになることもあるよ。
ケース1: DATEをTIMESTAMPの代わりに使っちゃう
イベントが日付だけじゃなくて時間も持ってるのに、DATEだけで記録しちゃうと、大事な情報を失うことになる。
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
order_date DATE -- 日付だけ
);
こんな設計だと、朝と夜に注文があったかどうかも分からない。せっかくコーヒー飲みながら、きれいなタイムスタンプを眺めるチャンスを逃すことになるよ?
ケース2: タイムゾーンを忘れる
アプリが海外ユーザーにも対応してるのに、TIMESTAMPだけで日付と時間を保存して、タイムゾーンを考慮しないと、データが「ホームレス」状態になる。TIMESTAMPTZならこの問題を解決できるよ。
CREATE TABLE events (
event_time TIMESTAMP -- タイムゾーンなし
);
誰もニューヨークの夜のイベントと東京の朝のイベントを間違えたくないでしょ。TIMESTAMPTZを使おう!
関数の使い方のミス
ケース1: TO_CHAR()のフォーマットミス
フォーマットを間違えると、問題が始まる。例えば:
SELECT TO_CHAR(NOW(), 'YYYY-DD-MM'); -- あっ、月と日を逆にしちゃった
これだと普通の年-月-日じゃなくて、年-日-月になっちゃう。ユーザーにとっては笑える(けど嬉しくない)状況になるかも。フォーマットは必ずチェックしよう。
ケース2: TO_DATE()の使い方ミス
逆に、文字列を日付に変換しようとしてフォーマットが合ってないと、PostgreSQLはエラーを返す。
SELECT TO_DATE('10/31/2023', 'YYYY-MM-DD'); -- エラー!フォーマットが合ってない。
文字列のフォーマットは、指定したものとピッタリ合ってないとダメ。例えば:
SELECT TO_DATE('2023-10-31', 'YYYY-MM-DD'); -- これならOK。
時間のインターバルでのミス
ケース1: 暗黙の型変換を忘れる
型変換のクセを忘れがち。例えば:
SELECT NOW() + '1'; -- エラー!'1'って何?
PostgreSQLは「1日足したい」って意味が分からない。正しいやり方は:
SELECT NOW() + INTERVAL '1 day';
ケース2: インターバルの引き算で混乱
インターバルを足したり引いたりする時は注意:
SELECT NOW() - INTERVAL '-1 day'; -- これだと1日足しちゃう!
マイナスが二重になると逆の効果になる。こういう書き方は避けよう。
丸めや切り捨てのミス
ケース1: DATE_TRUNC()の切り捨てミス
DATE_TRUNC()でデータをグループ化する時は、ちゃんと必要なレベルを選んでるか確認しよう。例えば:
SELECT DATE_TRUNC('hour', NOW()); -- 時間の先頭に切り捨て
SELECT DATE_TRUNC('minute', NOW()); -- 分の先頭に切り捨て
期待した結果と違うなら、レベルの選び方を間違えてるかも。
ケース2: DATE_TRUNC()でタイムゾーンを忘れる
いろんなタイムゾーンの時間を扱う時、結果が予想外になることも:
SELECT DATE_TRUNC('day', NOW() AT TIME ZONE 'UTC');
タイムゾーンがちゃんと指定されてるか確認しないと、本当に時間の迷子になるよ。
Unix時間:失われた秒
Unix時間(EPOCH)は便利だけど、ちょっとクセがある。よくあるミスは、秒とミリ秒を混同しちゃうこと。
SELECT TO_TIMESTAMP(1680000000); -- これが正しい(秒)。
SELECT TO_TIMESTAMP(1680000000000); -- これはミス!ゼロが多すぎ。
タイムスタンプが何単位か、ちゃんと確認して、余計な秒を保存しないようにしよう。
タイムゾーンでのミス
ケース1: ややこしいタイムゾーン
いろんなタイムゾーンのユーザーとやりとりしてると、データが混ざっちゃうことも。例えば:
SELECT TIMESTAMP '2023-10-01 10:00:00' AT TIME ZONE 'UTC';
どのタイムゾーンのデータなのか、ちゃんと把握しておこう。
ケース2: タイムゾーンの二重指定
日付と時間を保存してから、さらにタイムゾーンを指定しようとするのはNG:
SELECT TIMESTAMP '2023-10-01 10:00:00 UTC' AT TIME ZONE 'UTC'; -- こういうのはやめよう!
これだと計算が間違っちゃう。
ミスを防ぐためのアドバイス
適切なデータ型を選ぼう。 国際的な時間データを扱うならTIMESTAMPTZを使おう。日付だけで十分ならDATEでOK。
クエリをテストしよう。 結果が期待通りか必ず確認しよう。特にインターバルやフォーマット、丸め処理を使う時は注意。
時間データはUTCで保存しよう。 タイムゾーンの混乱を避けるにはこれが一番。
フォーマットを確認しよう。 TO_CHAR()やTO_DATE()のフォーマットがデータと合ってるかチェックしよう。
関数は慎重に使おう。 PostgreSQLの時間系関数のドキュメントをちゃんと読んで、思わぬトラブルを避けよう。
時間データの扱いは簡単じゃないけど、ちゃんと気をつけてやればスムーズにいくよ。日付と時間はアプリの大事な部分だし、月曜の朝にアラームかけ忘れるくらい危険だからね!
GO TO FULL VERSION