PostgreSQL現在日付の取得完全ガイド!CURRENT_DATEからNOW()まで使い分けマスター

データベース・SQL

「今日の日付を取得したいだけなのに、色々な関数があって迷う…」
「CURRENT_DATEとNOW()って何が違うの?」
「タイムゾーンとか考えると訳わからない…」

PostgreSQLで日付を扱う時、こんな悩みありませんか?

実は、PostgreSQLには現在の日付・時刻を取得する方法がたくさんあるんです。それぞれに特徴があって、使い分けることで、より正確で効率的なデータベース処理ができます。

この記事を読めば、状況に応じて最適な日付取得方法を選べるようになり、タイムゾーンの罠にもハマらなくなります!


スポンサーリンク

今すぐ使える!現在日付を取得する5つの方法

方法1:CURRENT_DATE(日付だけ欲しい時)

一番シンプルに「今日の日付」だけを取得する方法です。

SELECT CURRENT_DATE;
-- 結果: 2024-12-27

-- テーブルに挿入する例
INSERT INTO orders (order_date, product_id) 
VALUES (CURRENT_DATE, 100);

特徴:

  • 時刻情報なし(00:00:00として扱われる)
  • DATE型で返される
  • タイムゾーンの影響を受ける

こんな時に使う:

  • 営業日の記録
  • 誕生日の管理
  • 日次レポートの日付

方法2:NOW()(日付と時刻両方欲しい時)

現在の日付と時刻を両方取得する、最もよく使われる関数です。

SELECT NOW();
-- 結果: 2024-12-27 14:30:45.123456+09

-- 作成日時の記録
INSERT INTO posts (title, created_at) 
VALUES ('新しい記事', NOW());

特徴:

  • TIMESTAMP WITH TIME ZONE型で返される
  • マイクロ秒まで記録
  • タイムゾーン情報付き

こんな時に使う:

  • ログの記録
  • 作成・更新日時の管理
  • タイムスタンプが必要な処理全般

方法3:CURRENT_TIMESTAMP(NOW()とほぼ同じ)

SQL標準の関数で、NOW()とほぼ同じ動作をします。

SELECT CURRENT_TIMESTAMP;
-- 結果: 2024-12-27 14:30:45.123456+09

-- 精度を指定することも可能
SELECT CURRENT_TIMESTAMP(0);  -- 秒まで
-- 結果: 2024-12-27 14:30:45+09

SELECT CURRENT_TIMESTAMP(3);  -- ミリ秒まで
-- 結果: 2024-12-27 14:30:45.123+09

NOW()との違い:

  • 精度を指定できる
  • SQL標準準拠
  • 他のデータベースとの互換性が高い

方法4:CURRENT_TIME(時刻だけ欲しい時)

現在の時刻のみを取得します。

SELECT CURRENT_TIME;
-- 結果: 14:30:45.123456+09

-- 精度指定も可能
SELECT CURRENT_TIME(0);
-- 結果: 14:30:45+09

こんな時に使う:

  • 営業時間の判定
  • 定時処理の時刻記録
  • 時刻のみの比較処理

方法5:LOCALTIMESTAMP(タイムゾーンなし)

タイムゾーン情報を含まない現在日時を取得します。

SELECT LOCALTIMESTAMP;
-- 結果: 2024-12-27 14:30:45.123456

-- NOW()との比較
SELECT 
    NOW() AS with_tz,
    LOCALTIMESTAMP AS without_tz;

使い分けのポイント:

  • アプリケーション側でタイムゾーンを管理する場合
  • すべてのデータを同一タイムゾーンで扱う場合

日付の加工テクニック集

日付の切り捨て・切り上げ

DATE_TRUNCを使って、指定した単位で切り捨てができます。

-- 現在時刻を時間単位で切り捨て
SELECT DATE_TRUNC('hour', NOW());
-- 結果: 2024-12-27 14:00:00+09

-- 月初めの日付を取得
SELECT DATE_TRUNC('month', CURRENT_DATE);
-- 結果: 2024-12-01

-- 週の始まり(月曜日)を取得
SELECT DATE_TRUNC('week', CURRENT_DATE);

使える単位:

  • ‘year’:年
  • ‘quarter’:四半期
  • ‘month’:月
  • ‘week’:週
  • ‘day’:日
  • ‘hour’:時
  • ‘minute’:分
  • ‘second’:秒

日付の計算

INTERVALを使った日付計算が便利です。

-- 明日の日付
SELECT CURRENT_DATE + INTERVAL '1 day';

-- 1週間前
SELECT CURRENT_DATE - INTERVAL '7 days';

-- 3ヶ月後
SELECT CURRENT_DATE + INTERVAL '3 months';

-- 複雑な計算も可能
SELECT NOW() + INTERVAL '1 year 2 months 3 days 4 hours';

実用例:有効期限の設定

-- 30日間有効なクーポンを作成
INSERT INTO coupons (code, expires_at) 
VALUES ('SAVE10', CURRENT_DATE + INTERVAL '30 days');

日付のフォーマット

TO_CHARを使って、好きな形式で表示できます。

-- 日本式の表記
SELECT TO_CHAR(NOW(), 'YYYY年MM月DD日');
-- 結果: 2024年12月27日

-- 曜日付き
SELECT TO_CHAR(NOW(), 'YYYY-MM-DD (Day)');
-- 結果: 2024-12-27 (Friday   )

-- 時刻も含めて
SELECT TO_CHAR(NOW(), 'YYYY/MM/DD HH24:MI:SS');
-- 結果: 2024/12/27 14:30:45

-- AM/PM表記
SELECT TO_CHAR(NOW(), 'YYYY-MM-DD HH12:MI:SS AM');
-- 結果: 2024-12-27 02:30:45 PM

よく使うフォーマット文字:

  • YYYY:4桁の年
  • MM:2桁の月(01-12)
  • DD:2桁の日(01-31)
  • HH24:24時間制の時(00-23)
  • HH12:12時間制の時(01-12)
  • MI:分(00-59)
  • SS:秒(00-59)

タイムゾーンの扱い方

タイムゾーンの確認と設定

-- 現在のタイムゾーン設定を確認
SHOW timezone;
-- 結果: Asia/Tokyo

-- セッション単位でタイムゾーンを変更
SET timezone = 'America/New_York';

-- UTCに設定
SET timezone = 'UTC';

タイムゾーン変換

AT TIME ZONEを使った変換方法です。

-- 東京時間をニューヨーク時間に変換
SELECT NOW() AT TIME ZONE 'America/New_York';

-- UTCに変換
SELECT NOW() AT TIME ZONE 'UTC';

-- 複数のタイムゾーンで表示
SELECT 
    NOW() AS tokyo_time,
    NOW() AT TIME ZONE 'UTC' AS utc_time,
    NOW() AT TIME ZONE 'America/Los_Angeles' AS la_time;

実用例:世界各地の現在時刻

SELECT 
    'Tokyo' AS city, 
    (NOW() AT TIME ZONE 'Asia/Tokyo')::TIME AS local_time
UNION ALL
SELECT 
    'London', 
    (NOW() AT TIME ZONE 'Europe/London')::TIME
UNION ALL
SELECT 
    'New York', 
    (NOW() AT TIME ZONE 'America/New_York')::TIME;

実践的な使用例

デフォルト値として使う

テーブル作成時にデフォルト値として設定する方法です。

-- created_atカラムに自動で現在時刻を設定
CREATE TABLE articles (
    id SERIAL PRIMARY KEY,
    title VARCHAR(255),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

-- CURRENT_TIMESTAMPも使える
CREATE TABLE logs (
    id SERIAL PRIMARY KEY,
    message TEXT,
    logged_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

日付での条件検索

-- 今日のデータを取得
SELECT * FROM orders 
WHERE order_date = CURRENT_DATE;

-- 過去7日間のデータ
SELECT * FROM logs 
WHERE created_at >= CURRENT_DATE - INTERVAL '7 days';

-- 今月のデータ
SELECT * FROM sales 
WHERE DATE_TRUNC('month', sale_date) = DATE_TRUNC('month', CURRENT_DATE);

-- 営業時間内の判定(9:00-18:00)
SELECT * FROM appointments 
WHERE CURRENT_TIME BETWEEN TIME '09:00:00' AND TIME '18:00:00';

年齢計算

誕生日から現在の年齢を計算する方法です。

-- AGE関数を使う方法
SELECT 
    name,
    birth_date,
    AGE(CURRENT_DATE, birth_date) AS age
FROM users;

-- 年数だけ取得
SELECT 
    name,
    EXTRACT(YEAR FROM AGE(CURRENT_DATE, birth_date)) AS age_years
FROM users;

-- 誕生日が今日の人を探す
SELECT * FROM users 
WHERE 
    EXTRACT(MONTH FROM birth_date) = EXTRACT(MONTH FROM CURRENT_DATE)
    AND EXTRACT(DAY FROM birth_date) = EXTRACT(DAY FROM CURRENT_DATE);

よくあるトラブルと解決法

トラブル1:タイムゾーンの不一致

-- 問題:異なるタイムゾーンでデータが保存されている
-- 解決:統一的にUTCで保存し、表示時に変換

-- 保存時はUTC
INSERT INTO events (event_time) 
VALUES (NOW() AT TIME ZONE 'UTC');

-- 表示時にローカルタイムに変換
SELECT 
    event_time AT TIME ZONE 'Asia/Tokyo' AS local_time 
FROM events;

トラブル2:日付の比較がうまくいかない

-- 問題:TIMESTAMPとDATEの比較
-- NG例
SELECT * FROM orders 
WHERE created_at = '2024-12-27';  -- 時刻があるため一致しない

-- OK例
SELECT * FROM orders 
WHERE DATE(created_at) = '2024-12-27';

-- または
SELECT * FROM orders 
WHERE created_at >= '2024-12-27' 
AND created_at < '2024-12-28';

トラブル3:NULL値の扱い

-- COALESCE を使ってNULLの場合のデフォルト値を設定
SELECT 
    COALESCE(updated_at, created_at, NOW()) AS last_modified 
FROM articles;

-- NULLの場合は現在日付を使う
UPDATE tasks 
SET completed_at = COALESCE(completed_at, NOW()) 
WHERE status = 'completed';

パフォーマンスを考慮した日付処理

インデックスを活用した高速検索

-- 日付カラムにインデックスを作成
CREATE INDEX idx_orders_date ON orders(order_date);

-- 範囲検索に有効
CREATE INDEX idx_logs_created ON logs(created_at);

-- 関数インデックスも使える
CREATE INDEX idx_events_month ON events(DATE_TRUNC('month', event_date));

集計処理の最適化

-- 日別の集計
SELECT 
    DATE(created_at) AS date,
    COUNT(*) AS count
FROM orders
WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(created_at)
ORDER BY date;

-- 時間帯別の分析
SELECT 
    EXTRACT(HOUR FROM created_at) AS hour,
    COUNT(*) AS count
FROM access_logs
WHERE DATE(created_at) = CURRENT_DATE
GROUP BY EXTRACT(HOUR FROM created_at)
ORDER BY hour;

まとめ:状況に応じて最適な日付関数を選ぼう!

ここまで読んでいただき、ありがとうございました!

今すぐ使える選び方ガイド

用途別の使い分け:

  1. 日付だけ必要CURRENT_DATE
  2. 日付と時刻が必要NOW() または CURRENT_TIMESTAMP
  3. 時刻だけ必要CURRENT_TIME
  4. タイムゾーンなしLOCALTIMESTAMP

覚えておくべき3つのポイント

  1. NOW()が最も汎用的
  • 大抵の場合はこれでOK
  • タイムゾーン付きで安心
  1. DATE_TRUNCとINTERVALは超便利
  • 日付の切り捨てと計算の基本
  • これだけで大抵の処理ができる
  1. タイムゾーンは最初に決める
  • UTCで統一するか、ローカルタイムか
  • 後から変更は大変

よく使うパターン集

今日のデータ取得:

WHERE DATE(column) = CURRENT_DATE

過去N日間:

WHERE column >= CURRENT_DATE - INTERVAL 'N days'

今月のデータ:

WHERE DATE_TRUNC('month', column) = DATE_TRUNC('month', CURRENT_DATE)

PostgreSQLの日付関数をマスターすれば、時系列データの処理が格段に楽になります。

まずは基本のCURRENT_DATEとNOW()から始めて、徐々に応用的な使い方を覚えていきましょう!

コメント

タイトルとURLをコピーしました