Oracle で「今日の 0 時 0 分 0 秒」を取得するには TRUNC(SYSDATE) を使います。たった 1 つの関数呼び出しですが、日次バッチの実行判定、日別集計の WHERE 条件、ログのフィルタリングなど実務で最も多用される日付テクニックの 1 つです。
本記事では、今日の 0:00 の取得方法を起点に、今日の 23:59:59、「今日」「昨日」「今週」「今月」「過去 N 日」の WHERE 条件パターン、TIMESTAMP 型での 0:00、タイムゾーンを考慮した取得まで網羅します。
この記事でわかること
・TRUNC(SYSDATE) で今日の 0:00 を取得する方法
・今日の 23:59:59(当日の終了時刻)の取得
・WHERE 句での日付範囲フィルタパターン(今日/昨日/今週/今月/過去N日)
・TIMESTAMP 型で 0:00 を取得する方法
・SYSDATE と CURRENT_DATE の違い(タイムゾーン)
・日次バッチ・ログフィルタの実務パターン
・TRUNC(SYSDATE) で今日の 0:00 を取得する方法
・今日の 23:59:59(当日の終了時刻)の取得
・WHERE 句での日付範囲フィルタパターン(今日/昨日/今週/今月/過去N日)
・TIMESTAMP 型で 0:00 を取得する方法
・SYSDATE と CURRENT_DATE の違い(タイムゾーン)
・日次バッチ・ログフィルタの実務パターン
今日の 0:00 を取得する:TRUNC(SYSDATE)
SQL(基本)
-- 今日の 0:00:00 を取得 SELECT TRUNC(SYSDATE) AS today_start FROM DUAL; -- 結果例: 2026-03-28 00:00:00 -- 確認: 時刻が 00:00:00 であることを TO_CHAR で表示 SELECT TO_CHAR(TRUNC(SYSDATE), 'YYYY-MM-DD HH24:MI:SS') AS today_start FROM DUAL; -- 結果: 2026-03-28 00:00:00
TRUNC(SYSDATE) の動作
SYSDATE は現在の日付 + 時刻(例: 2026-03-28 14:35:22)を返します。TRUNC は時刻部分を切り捨てて 00:00:00 にします。結果は DATE 型のまま返るため、そのまま WHERE 条件に使えます。今日の 23:59:59 / 明日の 0:00 を取得する
SQL(当日終了時刻 / 明日の開始時刻)
-- 今日の 23:59:59(当日の最終秒) SELECT TRUNC(SYSDATE) + INTERVAL '23:59:59' HOUR TO SECOND AS today_end FROM DUAL; -- 明日の 0:00:00(翌日の開始) SELECT TRUNC(SYSDATE) + 1 AS tomorrow_start FROM DUAL; -- 昨日の 0:00:00 SELECT TRUNC(SYSDATE) - 1 AS yesterday_start FROM DUAL; -- 今日の 0:00 から 1 秒前 = 昨日の 23:59:59 SELECT TRUNC(SYSDATE) - INTERVAL '1' SECOND AS yesterday_end FROM DUAL;
日付範囲は「< 翌日の 0:00」で指定する
「今日の 23:59:59」を使うと、23:59:59.001〜23:59:59.999 のデータが漏れます。日付範囲のフィルタは
「今日の 23:59:59」を使うと、23:59:59.001〜23:59:59.999 のデータが漏れます。日付範囲のフィルタは
>= 今日の 0:00 AND < 明日の 0:00 と書くのが正確です。後述の WHERE 条件パターンで詳しく説明します。今日を起点にした各種日付の取得
| 取得したい日付 | SQL | 結果例(2026-03-28 基準) |
|---|---|---|
| 今日の 0:00 | TRUNC(SYSDATE) | 2026-03-28 00:00:00 |
| 明日の 0:00 | TRUNC(SYSDATE) + 1 | 2026-03-29 00:00:00 |
| 昨日の 0:00 | TRUNC(SYSDATE) – 1 | 2026-03-27 00:00:00 |
| N 日前の 0:00 | TRUNC(SYSDATE) – N | (N=7 → 2026-03-21) |
| 今週月曜の 0:00 | TRUNC(SYSDATE, ‘IW’) | 2026-03-23 00:00:00 |
| 今月 1 日の 0:00 | TRUNC(SYSDATE, ‘MM’) | 2026-03-01 00:00:00 |
| 今年 1 月 1 日の 0:00 | TRUNC(SYSDATE, ‘YYYY’) | 2026-01-01 00:00:00 |
| 今月末の 23:59:59 | LAST_DAY(TRUNC(SYSDATE)) + 1 – INTERVAL ‘1’ SECOND | 2026-03-31 23:59:59 |
| 翌月 1 日の 0:00 | TRUNC(ADD_MONTHS(SYSDATE, 1), ‘MM’) | 2026-04-01 00:00:00 |
TRUNC の日付フォーマット引数(’IW’、’MM’、’YYYY’ 等)の詳細は「TRUNC 関数で日付を切り捨てる方法」を参照してください。
WHERE 句での日付範囲フィルタパターン
日付の範囲指定は「>= 開始日の 0:00 AND < 終了日の翌日 0:00」が鉄則です。<= で「23:59:59」を使うと秒未満のデータが漏れるため、< で「翌日の 0:00」を使います。
今日のデータだけ取得
SQL(今日のデータ)
-- 推奨: >= 今日 0:00 AND < 明日 0:00 SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) AND order_date < TRUNC(SYSDATE) + 1; -- NG: BETWEEN で 23:59:59 を使うと秒未満が漏れる可能性 -- WHERE order_date BETWEEN TRUNC(SYSDATE) AND TRUNC(SYSDATE) + 1 - 1/86400
昨日のデータだけ取得
SQL(昨日のデータ)
SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) - 1 AND order_date < TRUNC(SYSDATE);
今週のデータ(月曜開始)
SQL(今週のデータ)
-- IW: ISO 週(月曜始まり) SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE, 'IW') AND order_date < TRUNC(SYSDATE, 'IW') + 7;
今月のデータ
SQL(今月のデータ)
SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE, 'MM') AND order_date < TRUNC(ADD_MONTHS(SYSDATE, 1), 'MM');
過去 N 日間のデータ
SQL(過去 7 日間 / 30 日間)
-- 過去 7 日間(今日含む) SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) - 7 AND order_date < TRUNC(SYSDATE) + 1; -- 過去 30 日間(今日含む) SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) - 30 AND order_date < TRUNC(SYSDATE) + 1;
今年のデータ
SQL(今年のデータ)
SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE, 'YYYY') AND order_date < TRUNC(ADD_MONTHS(SYSDATE, 12), 'YYYY');
日付範囲フィルタの鉄則
・開始:
・終了:
この書き方なら DATE 型でも TIMESTAMP 型でも正確に動作し、秒未満のデータも漏れません。
・開始:
>= 開始日の 0:00・終了:
< 終了日の翌日 0:00(「<」であり「<=」ではない)この書き方なら DATE 型でも TIMESTAMP 型でも正確に動作し、秒未満のデータも漏れません。
TIMESTAMP 型で 0:00 を取得する
SQL(TIMESTAMP 型での 0:00)
-- TIMESTAMP 型で今日の 0:00 を取得 SELECT CAST(TRUNC(SYSDATE) AS TIMESTAMP) AS today_ts FROM DUAL; -- 結果: 2026-03-28 00:00:00.000000 -- SYSTIMESTAMP から時刻を切り捨て SELECT TRUNC(SYSTIMESTAMP) AS today_ts FROM DUAL; -- 結果: DATE 型(00:00:00)が返る -- TIMESTAMP WITH TIME ZONE で今日の 0:00 SELECT CAST(TRUNC(CURRENT_DATE) AS TIMESTAMP WITH TIME ZONE) AS today_tz FROM DUAL;
タイムゾーンを考慮した 0:00 の取得
| 関数 | 基準タイムゾーン | 用途 |
|---|---|---|
| TRUNC(SYSDATE) | DB サーバーのOS タイムゾーン | サーバーが日本にある場合は JST |
| TRUNC(CURRENT_DATE) | セッションのタイムゾーン | クライアントのタイムゾーンに合わせたい場合 |
SQL(タイムゾーン確認と CURRENT_DATE)
-- DB サーバーのタイムゾーン確認 SELECT DBTIMEZONE FROM DUAL; -- セッションのタイムゾーン確認 SELECT SESSIONTIMEZONE FROM DUAL; -- セッションタイムゾーンを変更して確認 ALTER SESSION SET TIME_ZONE = '+09:00'; -- JST SELECT TRUNC(CURRENT_DATE) AS today_jst FROM DUAL; ALTER SESSION SET TIME_ZONE = '-05:00'; -- EST SELECT TRUNC(CURRENT_DATE) AS today_est FROM DUAL; -- DB サーバーが JST の場合、EST だと日付が 1 日ずれることがある
海外サーバーでは SYSDATE に注意
AWS RDS など海外リージョンの DB サーバーは UTC がデフォルトです。TRUNC(SYSDATE) は UTC の 0:00 になり、日本時間の 0:00 とは 9 時間ずれます。日本時間で「今日」を判定する場合は
AWS RDS など海外リージョンの DB サーバーは UTC がデフォルトです。TRUNC(SYSDATE) は UTC の 0:00 になり、日本時間の 0:00 とは 9 時間ずれます。日本時間で「今日」を判定する場合は
TRUNC(SYSDATE + INTERVAL '9' HOUR) または TRUNC(CURRENT_DATE)(セッションを JST に設定)を使ってください。よくある間違い
SQL(SYSDATE = TRUNC(SYSDATE) は通常 FALSE)
-- NG: SYSDATE は時刻を含むため、TRUNC と一致しない SELECT * FROM orders WHERE order_date = TRUNC(SYSDATE); -- → 0:00:00 ちょうどに登録されたデータしか取れない -- OK: 範囲指定で「今日」のデータを取得 SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) AND order_date < TRUNC(SYSDATE) + 1;
SQL(TO_CHAR で比較する間違い)
-- NG: 文字列比較(インデックスが効かない + 遅い) SELECT * FROM orders WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = TO_CHAR(SYSDATE, 'YYYY-MM-DD'); -- OK: DATE 同士の範囲比較(インデックスが効く) SELECT * FROM orders WHERE order_date >= TRUNC(SYSDATE) AND order_date < TRUNC(SYSDATE) + 1;
実務パターン集
パターン(1): 日次バッチの処理対象を「昨日のデータ」にする
SQL(日次バッチ: 昨日 0:00〜今日 0:00)
-- 毎朝実行するバッチ: 昨日のデータを集計
INSERT INTO daily_summary (summary_date, total_orders, total_amount)
SELECT
TRUNC(SYSDATE) - 1 AS summary_date,
COUNT(*),
SUM(amount)
FROM orders
WHERE order_date >= TRUNC(SYSDATE) - 1
AND order_date < TRUNC(SYSDATE);
パターン(2): 今日更新されたレコードを抽出
SQL(今日の更新分を抽出)
SELECT * FROM employees WHERE updated_at >= TRUNC(SYSDATE) ORDER BY updated_at DESC;
パターン(3): 日別の件数集計
SQL(過去 7 日間の日別件数)
SELECT
TRUNC(order_date) AS order_day,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
WHERE order_date >= TRUNC(SYSDATE) - 7
AND order_date < TRUNC(SYSDATE) + 1
GROUP BY TRUNC(order_date)
ORDER BY order_day;
パターン(4): 特定時刻の取得(今日の 9:00 / 18:00)
SQL(今日の特定時刻)
-- 今日の 9:00 SELECT TRUNC(SYSDATE) + 9/24 AS today_9am FROM DUAL; -- 今日の 18:00 SELECT TRUNC(SYSDATE) + 18/24 AS today_6pm FROM DUAL; -- INTERVAL を使う方法 SELECT TRUNC(SYSDATE) + INTERVAL '9' HOUR AS today_9am FROM DUAL; SELECT TRUNC(SYSDATE) + INTERVAL '18' HOUR AS today_6pm FROM DUAL; -- 営業時間内(9:00〜18:00)のデータ SELECT * FROM access_log WHERE log_time >= TRUNC(SYSDATE) + INTERVAL '9' HOUR AND log_time < TRUNC(SYSDATE) + INTERVAL '18' HOUR;
よくある質問
QTRUNC(SYSDATE) の結果は DATE 型ですか?TIMESTAMP 型ですか?
A
TRUNC(SYSDATE) は DATE 型を返します。TIMESTAMP 型が必要な場合は CAST(TRUNC(SYSDATE) AS TIMESTAMP) で変換してください。QWHERE order_date = TRUNC(SYSDATE) で今日のデータが取れません
A
= だと「ちょうど 0:00:00」に作成されたデータしかマッチしません。時刻を含む DATE 列に対しては >= TRUNC(SYSDATE) AND < TRUNC(SYSDATE) + 1 と範囲指定してください。QSYSDATE と CURRENT_DATE はどちらを使うべきですか?
ADB サーバーが日本国内にある場合は
SYSDATE で問題ありません。AWS RDS など海外リージョンのサーバーでは SYSDATE が UTC になるため、CURRENT_DATE(セッションタイムゾーン基準)を使うか、SYSDATE + INTERVAL '9' HOUR で JST に補正してください。詳細は「SYSDATE・SYSTIMESTAMP の違い」を参照。QTO_CHAR で日付を文字列比較するのはダメですか?
A
WHERE TO_CHAR(order_date, 'YYYY-MM-DD') = '2026-03-28' は動作しますが、インデックスが効きません(order_date 列に関数を適用するため)。WHERE order_date >= DATE '2026-03-28' AND order_date < DATE '2026-03-29' の方がインデックスが活用でき高速です。Q今日の 23:59:59 で範囲指定しても大丈夫ですか?
ADATE 型(秒精度)なら問題ないことが多いですが、TIMESTAMP 型(ミリ秒以下を含む)では 23:59:59.001〜23:59:59.999 が漏れます。安全のため「
< 翌日の 0:00」で指定する方が確実です。QTRUNC(SYSDATE) にインデックスは効きますか?
AWHERE 句で
TRUNC(order_date) のように列に TRUNC を適用すると、通常のインデックスは効きません。列はそのままで WHERE order_date >= TRUNC(SYSDATE) と書けばインデックスが活用されます。どうしても TRUNC(列) で検索したい場合は関数ベースインデックスを作成してください。まとめ
今日の 0:00 を起点にした日付操作の要点をまとめます。
| やりたいこと | SQL |
|---|---|
| 今日の 0:00 を取得 | TRUNC(SYSDATE) |
| 明日の 0:00 を取得 | TRUNC(SYSDATE) + 1 |
| 今日のデータを WHERE で抽出 | WHERE col >= TRUNC(SYSDATE) AND col < TRUNC(SYSDATE) + 1 |
| 昨日のデータを抽出 | WHERE col >= TRUNC(SYSDATE) – 1 AND col < TRUNC(SYSDATE) |
| 今週(月曜〜)のデータを抽出 | WHERE col >= TRUNC(SYSDATE, ‘IW’) AND col < TRUNC(SYSDATE, ‘IW’) + 7 |
| 今月のデータを抽出 | WHERE col >= TRUNC(SYSDATE, ‘MM’) AND col < TRUNC(ADD_MONTHS(SYSDATE,1), ‘MM’) |
| 過去 N 日間を抽出 | WHERE col >= TRUNC(SYSDATE) – N AND col < TRUNC(SYSDATE) + 1 |
| 今日の特定時刻(例: 9:00) | TRUNC(SYSDATE) + INTERVAL ‘9’ HOUR |
TRUNC の日付フォーマット引数の詳細は「TRUNC 関数で日付を切り捨てる方法」、SYSDATE / SYSTIMESTAMP / CURRENT_DATE の違いは「システム日付を取得する方法」、月末の取得は「月末を取得する方法」も併せて参照してください。
