PostgreSQLで現在時刻を取得する全方法!NOW()・CURRENT_TIMESTAMPの使い分けからタイムゾーン対応まで

データベース・SQL

「今の時刻をデータベースに記録したい」 「ログの記録時刻を正確に保存したい」 「日本時間?UTC?タイムゾーンがよくわからない…」

PostgreSQLで現在時刻を取得する方法、実はたくさんあるんです。 NOW()CURRENT_TIMESTAMPCURRENT_DATE… どれを使えばいいか、迷いますよね。

しかも、タイムゾーンの扱いを間違えると、 9時間ずれた時刻が記録されてしまうことも。

この記事では、PostgreSQLの時刻取得機能を完全に理解できるよう、 基本から応用まで、実例たっぷりでお伝えします。

正確な時刻管理で、信頼できるシステムを作りましょう!


スポンサーリンク
  1. 1. PostgreSQLの時刻取得関数、一覧で理解
    1. 🕐 主要な時刻取得関数の比較
    2. 🕐 実際に使ってみよう
  2. 2. NOW()関数:最も使われる現在時刻取得
    1. 📌 NOW()の基本的な使い方
    2. 📌 NOW()の特徴:トランザクション内で固定
    3. 📌 リアルタイムが必要な場合:CLOCK_TIMESTAMP()
  3. 3. CURRENT_TIMESTAMPとその仲間たち
    1. 📅 CURRENT_DATE:日付だけが欲しい時
    2. 📅 CURRENT_TIME:時刻だけが欲しい時
    3. 📅 精度の指定
  4. 4. タイムゾーンの理解と対処法
    1. 🌍 タイムゾーンの基本概念
    2. 🌍 タイムゾーンの変換
    3. 🌍 タイムゾーンを意識したテーブル設計
  5. 5. 日付・時刻の計算と操作
    1. ➕ 時刻の加算・減算
    2. ➕ 営業日の計算
    3. ➕ 年齢や経過時間の計算
  6. 6. フォーマット変換と表示形式
    1. 📝 TO_CHAR()で自由自在にフォーマット
    2. 📝 フォーマット記号一覧
    3. 📝 実用的なフォーマット例
  7. 7. パフォーマンスを意識した時刻処理
    1. ⚡ インデックスと時刻検索
    2. ⚡ パーティショニングでの活用
  8. 8. 実践的な使用例とベストプラクティス
    1. 💼 ケース1:監査ログの実装
    2. 💼 ケース2:有効期限管理
    3. 💼 ケース3:定期実行スケジュール
  9. 9. よくあるトラブルと解決方法
    1. ❌ 時刻が9時間ずれる問題
    2. ❌ 日付の境界での不具合
    3. ❌ NULL値での計算エラー
  10. 10. 高度なテクニックとTips
    1. 🎯 時系列データの集計
    2. 🎯 ウィンドウ関数での時刻処理
    3. 🎯 タイムゾーン変換のユーティリティ
  11. まとめ:正確な時刻管理で、信頼性の高いシステムを!
    1. 🚀 次のステップ

1. PostgreSQLの時刻取得関数、一覧で理解

🕐 主要な時刻取得関数の比較

まずは、どんな関数があるのか整理しましょう。

関数名戻り値の型タイムゾーン用途
NOW()timestamp with time zoneあり最も汎用的
CURRENT_TIMESTAMPtimestamp with time zoneありSQL標準
CURRENT_DATEdateなし日付のみ
CURRENT_TIMEtime with time zoneあり時刻のみ
LOCALTIMESTAMPtimestampなしローカル時刻
LOCALTIMEtimeなしローカル時刻(時刻のみ)

🕐 実際に使ってみよう

-- それぞれの関数を実行
SELECT 
    NOW() AS now_result,
    CURRENT_TIMESTAMP AS current_timestamp_result,
    CURRENT_DATE AS current_date_result,
    CURRENT_TIME AS current_time_result,
    LOCALTIMESTAMP AS localtimestamp_result,
    LOCALTIME AS localtime_result;

実行結果例:

now_result:               2025-01-15 14:30:45.123456+09
current_timestamp_result: 2025-01-15 14:30:45.123456+09
current_date_result:      2025-01-15
current_time_result:      14:30:45.123456+09
localtimestamp_result:    2025-01-15 14:30:45.123456
localtime_result:         14:30:45.123456

ポイント:

  • +09 はタイムゾーン情報(日本時間)
  • NOW() と CURRENT_TIMESTAMP は同じ結果
  • LOCAL系はタイムゾーン情報なし

2. NOW()関数:最も使われる現在時刻取得

📌 NOW()の基本的な使い方

-- 現在時刻を取得
SELECT NOW();
-- 結果: 2025-01-15 14:30:45.123456+09

-- テーブルに記録
CREATE TABLE access_logs (
    log_id SERIAL PRIMARY KEY,
    user_id INT,
    action VARCHAR(100),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- データ挿入時に自動で現在時刻が入る
INSERT INTO access_logs (user_id, action) 
VALUES (1, 'ログイン');

-- 確認
SELECT * FROM access_logs;

📌 NOW()の特徴:トランザクション内で固定

重要な特徴: NOW()はトランザクション開始時刻を返します。

BEGIN;

SELECT NOW();  -- 2025-01-15 14:30:00

-- 3秒待つ
SELECT pg_sleep(3);

SELECT NOW();  -- 2025-01-15 14:30:00(同じ時刻!)

COMMIT;

この特徴は、一連の処理に同じタイムスタンプを付けたい時に便利です。

📌 リアルタイムが必要な場合:CLOCK_TIMESTAMP()

BEGIN;

SELECT CLOCK_TIMESTAMP();  -- 2025-01-15 14:30:00.123456

SELECT pg_sleep(3);

SELECT CLOCK_TIMESTAMP();  -- 2025-01-15 14:30:03.456789(3秒後!)

COMMIT;

使い分け:

  • NOW(): トランザクション全体で一貫性が必要
  • CLOCK_TIMESTAMP(): 実行時点の正確な時刻が必要

3. CURRENT_TIMESTAMPとその仲間たち

📅 CURRENT_DATE:日付だけが欲しい時

-- 今日の日付を取得
SELECT CURRENT_DATE;
-- 結果: 2025-01-15

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

-- 今月の初日を計算
SELECT DATE_TRUNC('month', CURRENT_DATE) AS first_day_of_month;
-- 結果: 2025-01-01

-- 今月の最終日を計算
SELECT 
    DATE_TRUNC('month', CURRENT_DATE) + INTERVAL '1 month' - INTERVAL '1 day' 
    AS last_day_of_month;
-- 結果: 2025-01-31

📅 CURRENT_TIME:時刻だけが欲しい時

-- 現在時刻を取得
SELECT CURRENT_TIME;
-- 結果: 14:30:45.123456+09

-- 営業時間内かチェック
SELECT 
    CASE 
        WHEN CURRENT_TIME BETWEEN '09:00:00'::TIME AND '18:00:00'::TIME 
        THEN '営業時間内'
        ELSE '営業時間外'
    END AS business_status;

📅 精度の指定

-- マイクロ秒まで不要な場合は精度を指定
SELECT CURRENT_TIMESTAMP(0);  -- 秒まで: 2025-01-15 14:30:45+09
SELECT CURRENT_TIMESTAMP(3);  -- ミリ秒まで: 2025-01-15 14:30:45.123+09

-- NOW()でも同様
SELECT NOW()::TIMESTAMP(0);

4. タイムゾーンの理解と対処法

🌍 タイムゾーンの基本概念

PostgreSQLは、内部的には**UTC(協定世界時)**で時刻を保存します。 表示時に、設定されたタイムゾーンに変換されるんです。

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

-- サーバーのタイムゾーン一覧
SELECT * FROM pg_timezone_names 
WHERE name LIKE '%Tokyo%' OR name LIKE '%UTC%';

🌍 タイムゾーンの変換

-- 日本時間をUTCに変換
SELECT NOW() AT TIME ZONE 'UTC';

-- 具体例:日本時間 2025-01-15 14:00 → UTC 2025-01-15 05:00
SELECT 
    '2025-01-15 14:00:00+09'::TIMESTAMPTZ AS japan_time,
    '2025-01-15 14:00:00+09'::TIMESTAMPTZ AT TIME ZONE 'UTC' AS utc_time;

-- 異なるタイムゾーンで表示
SELECT 
    NOW() AS current_japan,
    NOW() AT TIME ZONE 'America/New_York' AS new_york,
    NOW() AT TIME ZONE 'Europe/London' AS london;

🌍 タイムゾーンを意識したテーブル設計

-- グローバルサービスのイベント記録
CREATE TABLE global_events (
    event_id SERIAL PRIMARY KEY,
    event_name VARCHAR(200),
    -- UTCで保存(推奨)
    event_time_utc TIMESTAMP WITH TIME ZONE,
    -- ローカル時刻も保存(表示用)
    event_time_local TIMESTAMP WITHOUT TIME ZONE,
    timezone_name VARCHAR(50)
);

-- データ挿入例
INSERT INTO global_events (
    event_name,
    event_time_utc,
    event_time_local,
    timezone_name
) VALUES (
    'オンラインセミナー',
    NOW(),
    NOW() AT TIME ZONE 'Asia/Tokyo',
    'Asia/Tokyo'
);

5. 日付・時刻の計算と操作

➕ 時刻の加算・減算

-- 基本的な計算
SELECT 
    NOW() AS current_time,
    NOW() + INTERVAL '1 hour' AS one_hour_later,
    NOW() - INTERVAL '30 minutes' AS thirty_min_ago,
    NOW() + INTERVAL '7 days' AS next_week,
    NOW() - INTERVAL '1 month' AS last_month;

-- 複数単位の計算
SELECT NOW() + INTERVAL '1 year 2 months 3 days 4 hours 5 minutes';

-- 動的な計算
SELECT NOW() + (INTERVAL '1 day' * 7) AS seven_days_later;

➕ 営業日の計算

-- 営業日を考慮した日付計算関数
CREATE OR REPLACE FUNCTION add_business_days(
    start_date DATE,
    days_to_add INT
) RETURNS DATE AS $$
DECLARE
    result_date DATE := start_date;
    days_added INT := 0;
BEGIN
    WHILE days_added < days_to_add LOOP
        result_date := result_date + 1;
        -- 土日をスキップ
        IF EXTRACT(DOW FROM result_date) NOT IN (0, 6) THEN
            days_added := days_added + 1;
        END IF;
    END LOOP;
    RETURN result_date;
END;
$$ LANGUAGE plpgsql;

-- 使用例:3営業日後
SELECT add_business_days(CURRENT_DATE, 3);

➕ 年齢や経過時間の計算

-- 年齢計算
SELECT 
    '1990-05-15'::DATE AS birth_date,
    AGE('1990-05-15'::DATE) AS age_interval,
    EXTRACT(YEAR FROM AGE('1990-05-15'::DATE)) AS years_old;

-- 経過時間の計算
SELECT 
    NOW() - '2025-01-15 09:00:00'::TIMESTAMP AS elapsed_time,
    EXTRACT(EPOCH FROM (NOW() - '2025-01-15 09:00:00'::TIMESTAMP)) AS seconds_elapsed;

-- 人間が読みやすい形式に変換
CREATE OR REPLACE FUNCTION format_duration(duration INTERVAL)
RETURNS TEXT AS $$
DECLARE
    years INT;
    months INT;
    days INT;
    hours INT;
    minutes INT;
BEGIN
    years := EXTRACT(YEAR FROM duration);
    months := EXTRACT(MONTH FROM duration);
    days := EXTRACT(DAY FROM duration);
    hours := EXTRACT(HOUR FROM duration);
    minutes := EXTRACT(MINUTE FROM duration);
    
    RETURN CONCAT_WS(', ',
        CASE WHEN years > 0 THEN years || '年' END,
        CASE WHEN months > 0 THEN months || 'ヶ月' END,
        CASE WHEN days > 0 THEN days || '日' END,
        CASE WHEN hours > 0 THEN hours || '時間' END,
        CASE WHEN minutes > 0 THEN minutes || '分' END
    );
END;
$$ LANGUAGE plpgsql;

-- 使用例
SELECT format_duration(NOW() - '2024-01-01'::TIMESTAMP);
-- 結果: 1年, 14日, 5時間, 30分

6. フォーマット変換と表示形式

📝 TO_CHAR()で自由自在にフォーマット

-- よく使うフォーマット例
SELECT 
    TO_CHAR(NOW(), 'YYYY-MM-DD') AS date_only,           -- 2025-01-15
    TO_CHAR(NOW(), 'YYYY/MM/DD HH24:MI:SS') AS datetime, -- 2025/01/15 14:30:45
    TO_CHAR(NOW(), 'YYYY年MM月DD日') AS japanese_date,   -- 2025年01月15日
    TO_CHAR(NOW(), 'Day') AS day_name,                   -- Wednesday
    TO_CHAR(NOW(), 'FMDD日 HH24時MI分') AS short_jp;     -- 15日 14時30分

📝 フォーマット記号一覧

-- 主要なフォーマット記号
SELECT 
    TO_CHAR(NOW(), 'YYYY') AS year_4digit,        -- 2025
    TO_CHAR(NOW(), 'YY') AS year_2digit,          -- 25
    TO_CHAR(NOW(), 'MM') AS month_number,         -- 01
    TO_CHAR(NOW(), 'Month') AS month_name,        -- January
    TO_CHAR(NOW(), 'Mon') AS month_abbr,          -- Jan
    TO_CHAR(NOW(), 'DD') AS day_of_month,         -- 15
    TO_CHAR(NOW(), 'D') AS day_of_week,           -- 4(水曜日)
    TO_CHAR(NOW(), 'HH24') AS hour_24,            -- 14
    TO_CHAR(NOW(), 'HH12') AS hour_12,            -- 02
    TO_CHAR(NOW(), 'MI') AS minute,               -- 30
    TO_CHAR(NOW(), 'SS') AS second,               -- 45
    TO_CHAR(NOW(), 'AM') AS am_pm;                -- PM

📝 実用的なフォーマット例

-- ログファイル名用
SELECT TO_CHAR(NOW(), 'YYYYMMDD_HH24MISS');
-- 結果: 20250115_143045

-- CSVエクスポート用
SELECT TO_CHAR(NOW(), 'YYYY-MM-DD"T"HH24:MI:SS"+09:00"');
-- 結果: 2025-01-15T14:30:45+09:00

-- 月次レポート用
SELECT TO_CHAR(NOW(), 'YYYY年FMMM月度');
-- 結果: 2025年1月度

-- 週次レポート用  
SELECT 
    TO_CHAR(NOW(), 'YYYY年 第IW週') AS week_number,
    TO_CHAR(DATE_TRUNC('week', NOW()), 'MM/DD') || '〜' || 
    TO_CHAR(DATE_TRUNC('week', NOW()) + INTERVAL '6 days', 'MM/DD') AS week_range;
-- 結果: 2025年 第03週, 01/13〜01/19

7. パフォーマンスを意識した時刻処理

⚡ インデックスと時刻検索

-- 時刻カラムにインデックスを作成
CREATE INDEX idx_created_at ON orders(created_at);

-- 日付のみのインデックス(日付検索が多い場合)
CREATE INDEX idx_created_date ON orders(DATE(created_at));

-- 効率的な範囲検索
-- 良い例:インデックスが効く
SELECT * FROM orders
WHERE created_at >= CURRENT_DATE 
  AND created_at < CURRENT_DATE + INTERVAL '1 day';

-- 悪い例:関数をカラムに適用(インデックスが効かない)
SELECT * FROM orders
WHERE DATE(created_at) = CURRENT_DATE;  -- 避けるべき

⚡ パーティショニングでの活用

-- 月別パーティションテーブル
CREATE TABLE events (
    event_id BIGSERIAL,
    event_time TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    event_data JSONB
) PARTITION BY RANGE (event_time);

-- 自動でパーティション作成
CREATE TABLE events_2025_01 PARTITION OF events
    FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');

CREATE TABLE events_2025_02 PARTITION OF events
    FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');

-- 古いパーティションの自動削除設定
CREATE OR REPLACE FUNCTION drop_old_partitions()
RETURNS void AS $$
DECLARE
    cutoff_date DATE;
BEGIN
    cutoff_date := CURRENT_DATE - INTERVAL '3 months';
    
    -- 3ヶ月以上前のパーティションを削除
    EXECUTE format('DROP TABLE IF EXISTS events_%s',
        TO_CHAR(cutoff_date, 'YYYY_MM'));
END;
$$ LANGUAGE plpgsql;

8. 実践的な使用例とベストプラクティス

💼 ケース1:監査ログの実装

-- 監査ログテーブル
CREATE TABLE audit_logs (
    audit_id BIGSERIAL PRIMARY KEY,
    table_name VARCHAR(50),
    operation VARCHAR(10),
    user_id INT,
    old_data JSONB,
    new_data JSONB,
    -- 更新不可の作成時刻
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    -- IPアドレスなど追加情報
    client_ip INET,
    session_id VARCHAR(100)
);

-- トリガー関数で自動記録
CREATE OR REPLACE FUNCTION audit_trigger_function()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO audit_logs (
        table_name,
        operation,
        user_id,
        old_data,
        new_data,
        client_ip,
        session_id
    ) VALUES (
        TG_TABLE_NAME,
        TG_OP,
        current_setting('app.current_user_id', true)::INT,
        CASE WHEN TG_OP = 'DELETE' THEN row_to_json(OLD) ELSE NULL END,
        CASE WHEN TG_OP IN ('INSERT', 'UPDATE') THEN row_to_json(NEW) ELSE NULL END,
        inet_client_addr(),
        current_setting('app.session_id', true)
    );
    
    RETURN CASE 
        WHEN TG_OP = 'DELETE' THEN OLD 
        ELSE NEW 
    END;
END;
$$ LANGUAGE plpgsql;

💼 ケース2:有効期限管理

-- クーポンテーブル
CREATE TABLE coupons (
    coupon_id SERIAL PRIMARY KEY,
    coupon_code VARCHAR(20) UNIQUE,
    discount_percent INT,
    valid_from TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    valid_until TIMESTAMP WITH TIME ZONE,
    is_active BOOLEAN GENERATED ALWAYS AS (
        NOW() BETWEEN valid_from AND valid_until
    ) STORED
);

-- 1週間有効なクーポンを作成
INSERT INTO coupons (coupon_code, discount_percent, valid_until)
VALUES ('WELCOME2025', 20, NOW() + INTERVAL '7 days');

-- 有効なクーポンのみ取得
SELECT * FROM coupons
WHERE NOW() BETWEEN valid_from AND valid_until;

-- もうすぐ期限切れのクーポン(24時間以内)
SELECT 
    coupon_code,
    valid_until,
    valid_until - NOW() AS time_remaining
FROM coupons
WHERE valid_until BETWEEN NOW() AND NOW() + INTERVAL '24 hours'
ORDER BY valid_until;

💼 ケース3:定期実行スケジュール

-- スケジュールテーブル
CREATE TABLE scheduled_tasks (
    task_id SERIAL PRIMARY KEY,
    task_name VARCHAR(100),
    cron_expression VARCHAR(50),
    last_run_at TIMESTAMP WITH TIME ZONE,
    next_run_at TIMESTAMP WITH TIME ZONE,
    is_active BOOLEAN DEFAULT TRUE
);

-- 次回実行時刻を計算する関数
CREATE OR REPLACE FUNCTION calculate_next_run(
    cron_expr VARCHAR,
    from_time TIMESTAMP WITH TIME ZONE DEFAULT NOW()
) RETURNS TIMESTAMP WITH TIME ZONE AS $$
DECLARE
    next_time TIMESTAMP WITH TIME ZONE;
BEGIN
    -- 簡略化した例(実際はcron式をパース)
    -- 毎日午前9時の場合
    IF cron_expr = '0 9 * * *' THEN
        next_time := DATE_TRUNC('day', from_time) + INTERVAL '1 day 9 hours';
        IF next_time <= from_time THEN
            next_time := next_time + INTERVAL '1 day';
        END IF;
    -- 毎時実行の場合
    ELSIF cron_expr = '0 * * * *' THEN
        next_time := DATE_TRUNC('hour', from_time) + INTERVAL '1 hour';
    END IF;
    
    RETURN next_time;
END;
$$ LANGUAGE plpgsql;

-- 実行すべきタスクを取得
SELECT * FROM scheduled_tasks
WHERE is_active = TRUE
  AND (next_run_at IS NULL OR next_run_at <= NOW())
ORDER BY next_run_at NULLS FIRST;

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

❌ 時刻が9時間ずれる問題

-- 原因確認:タイムゾーン設定
SHOW timezone;

-- セッション単位で修正
SET timezone = 'Asia/Tokyo';

-- データベース全体で設定
ALTER DATABASE mydb SET timezone = 'Asia/Tokyo';

-- 既存データの修正(UTCとして保存されていた場合)
UPDATE events
SET event_time = event_time AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Tokyo'
WHERE event_time < '2025-01-01';

❌ 日付の境界での不具合

-- 問題:23:59:59.999999 のデータが漏れる
-- 悪い例
SELECT * FROM orders
WHERE created_at BETWEEN '2025-01-15 00:00:00' AND '2025-01-15 23:59:59';

-- 良い例:半開区間を使用
SELECT * FROM orders
WHERE created_at >= '2025-01-15'::DATE
  AND created_at < '2025-01-16'::DATE;

-- または DATE_TRUNC を使用
SELECT * FROM orders
WHERE DATE_TRUNC('day', created_at) = '2025-01-15'::DATE;

❌ NULL値での計算エラー

-- NULL安全な時刻計算
SELECT 
    COALESCE(updated_at, created_at, NOW()) AS last_modified,
    GREATEST(created_at, updated_at) AS latest_time,
    LEAST(start_time, end_time) AS earliest_time
FROM tasks;

-- 経過時間計算でNULL対策
SELECT 
    task_name,
    CASE 
        WHEN completed_at IS NULL THEN '進行中'
        ELSE format_duration(completed_at - started_at)
    END AS duration
FROM tasks;

10. 高度なテクニックとTips

🎯 時系列データの集計

-- 時間帯別の集計
SELECT 
    DATE_TRUNC('hour', created_at) AS hour,
    COUNT(*) AS order_count,
    SUM(total_amount) AS total_sales
FROM orders
WHERE created_at >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY DATE_TRUNC('hour', created_at)
ORDER BY hour;

-- 曜日別の傾向分析
SELECT 
    TO_CHAR(created_at, 'Day') AS day_of_week,
    EXTRACT(DOW FROM created_at) AS day_number,
    COUNT(*) AS order_count,
    AVG(total_amount) AS avg_amount
FROM orders
WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY TO_CHAR(created_at, 'Day'), EXTRACT(DOW FROM created_at)
ORDER BY day_number;

🎯 ウィンドウ関数での時刻処理

-- 前回からの経過時間を計算
SELECT 
    user_id,
    login_time,
    LAG(login_time) OVER (PARTITION BY user_id ORDER BY login_time) AS prev_login,
    login_time - LAG(login_time) OVER (PARTITION BY user_id ORDER BY login_time) AS time_since_last
FROM user_logins
ORDER BY user_id, login_time;

-- 移動平均の計算
SELECT 
    DATE_TRUNC('day', order_date) AS day,
    daily_sales,
    AVG(daily_sales) OVER (
        ORDER BY DATE_TRUNC('day', order_date) 
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS moving_avg_7days
FROM (
    SELECT 
        order_date,
        SUM(total_amount) AS daily_sales
    FROM orders
    GROUP BY order_date
) daily_totals;

🎯 タイムゾーン変換のユーティリティ

-- 世界時計ビュー
CREATE VIEW world_clock AS
SELECT 
    'Tokyo' AS city,
    NOW() AS local_time
UNION ALL
SELECT 
    'New York',
    NOW() AT TIME ZONE 'America/New_York'
UNION ALL
SELECT 
    'London',
    NOW() AT TIME ZONE 'Europe/London'
UNION ALL
SELECT 
    'Sydney',
    NOW() AT TIME ZONE 'Australia/Sydney';

-- イベントの各地域での時刻表示
CREATE OR REPLACE FUNCTION show_event_times(
    event_time TIMESTAMP WITH TIME ZONE
) RETURNS TABLE (
    timezone_name TEXT,
    local_time TEXT,
    offset_from_utc TEXT
) AS $$
BEGIN
    RETURN QUERY
    SELECT 
        tz.name::TEXT,
        TO_CHAR(event_time AT TIME ZONE tz.name, 'YYYY-MM-DD HH24:MI:SS')::TEXT,
        tz.utc_offset::TEXT
    FROM pg_timezone_names tz
    WHERE tz.name IN (
        'Asia/Tokyo',
        'America/New_York',
        'Europe/London',
        'UTC'
    )
    ORDER BY tz.utc_offset;
END;
$$ LANGUAGE plpgsql;

まとめ:正確な時刻管理で、信頼性の高いシステムを!

PostgreSQLの現在時刻取得、思った以上に奥が深いですよね。 でも、基本を押さえれば、どんな要件にも対応できます。

重要ポイントのおさらい:

NOW()が最も汎用的

  • トランザクション内で一定
  • タイムゾーン付きで安全

用途に応じた使い分け

  • 日付のみ:CURRENT_DATE
  • リアルタイム:CLOCK_TIMESTAMP()
  • ローカル時刻:LOCALTIMESTAMP

タイムゾーンは必ず意識

  • データベースは内部的にUTC
  • WITH TIME ZONEを推奨
  • AT TIME ZONEで変換

フォーマットはTO_CHAR()で自在に

  • 日本語表示も可能
  • ログファイル名にも活用

使い分けガイド:

ケース使う関数理由
ログ記録NOW()一貫性が重要
有効期限CURRENT_TIMESTAMPSQL標準準拠
日次バッチCURRENT_DATE時刻不要
パフォーマンス測定CLOCK_TIMESTAMP()実時間必要

時刻の正確な管理は、システムの信頼性に直結します。 この記事を参考に、適切な時刻処理を実装してください。


🚀 次のステップ

今すぐ試すべきこと:

  1. NOW()とCLOCK_TIMESTAMP()の違いを確認
  2. タイムゾーン設定をチェック
  3. TO_CHAR()でフォーマット練習

スキルアップのために:

  1. pg_cronで定期実行を実装
  2. タイムゾーン変換の自動化
  3. 時系列データの分析に挑戦

この記事が、あなたのPostgreSQLでの 時刻処理スキル向上に役立つことを願っています!

正確な時刻管理で、ユーザーに信頼されるシステムを構築しましょう!

コメント

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