データベースを使っていて、「今日のデータだけ取得したい」「日付で並べ替えたい」「1週間以内の注文を抽出したい」といった場面はよくあります。
そんな時に欠かせないのが、SQLでの日付・時刻の扱いです。
この記事では、SQLにおける日付・時刻データの基本から、比較、抽出、フォーマット変換のテクニックまで、初心者にも分かりやすく解説します。
日付・時刻のデータ型を知ろう

主要なデータ型
SQLでは、日付や時刻を扱うために以下のデータ型が用意されています。
DATE型:日付のみ
- 保存形式:YYYY-MM-DD
- 例:2025-06-02
- 用途:誕生日、開始日、終了日など
TIME型:時刻のみ
- 保存形式:HH:MM:SS
- 例:14:30:00
- 用途:営業時間、開店時刻など
DATETIME型:日付と時刻
- 保存形式:YYYY-MM-DD HH:MM:SS
- 例:2025-06-02 14:30:00
- 用途:注文日時、更新日時など
TIMESTAMP型:タイムスタンプ
- 特徴:UNIX時間をベースにした日時
- 用途:レコードの作成・更新時刻の自動記録
テーブル作成の例
-- MySQL の例
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_name VARCHAR(100),
order_date DATETIME,
delivery_date DATE,
order_time TIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- データの挿入例
INSERT INTO orders (id, customer_name, order_date, delivery_date, order_time)
VALUES (1, '田中太郎', '2025-06-02 14:30:00', '2025-06-05', '14:30:00');
データ型の選び方
- 日付だけが必要:DATE型
- 時刻だけが必要:TIME型
- 日付と時刻の両方が必要:DATETIME型
- 自動で現在時刻を記録したい:TIMESTAMP型
ポイント
- データ型によって保存できる情報が変わる
- 目的に応じて適切なデータ型を選択
- 文字列ではなく専用のデータ型を使うことが重要
まずはデータ型を正しく理解することで、適切な比較や演算が可能になります。次は、よく使う日付関数を紹介します。
よく使う日付・時刻関数を覚えよう

現在の日付・時刻を取得する関数
-- 現在の日付と時刻を取得
SELECT NOW();
-- 結果例:2025-06-03 15:45:30
-- 現在の日付のみを取得
SELECT CURDATE();
-- 結果例:2025-06-03
-- 現在の時刻のみを取得
SELECT CURTIME();
-- 結果例:15:45:30
日付の一部を抽出する関数
-- DATETIME型から日付部分だけを抽出
SELECT DATE('2025-06-03 15:45:30');
-- 結果:2025-06-03
-- 年を抽出
SELECT YEAR('2025-06-03');
-- 結果:2025
-- 月を抽出
SELECT MONTH('2025-06-03');
-- 結果:6
-- 日を抽出
SELECT DAY('2025-06-03');
-- 結果:3
-- 曜日を抽出(1=日曜日、2=月曜日...)
SELECT DAYOFWEEK('2025-06-03');
-- 結果:3(火曜日)
日付の差を計算する関数
-- 日付の差を日数で計算
SELECT DATEDIFF('2025-06-10', '2025-06-01');
-- 結果:9
-- 今日から指定日まであと何日か
SELECT DATEDIFF('2025-12-31', CURDATE());
-- 年齢を計算(誕生日から今日まで)
SELECT FLOOR(DATEDIFF(CURDATE(), '1990-05-15') / 365.25) AS age;
日付を加算・減算する関数
-- 3日後の日付
SELECT DATE_ADD(CURDATE(), INTERVAL 3 DAY);
-- 1週間前の日付
SELECT DATE_SUB(CURDATE(), INTERVAL 1 WEEK);
-- 2ヶ月後の日付
SELECT DATE_ADD('2025-06-03', INTERVAL 2 MONTH);
-- 1年前の日付
SELECT DATE_SUB('2025-06-03', INTERVAL 1 YEAR);
よく使う時間単位
-- 様々な時間単位での加算例
SELECT DATE_ADD(NOW(), INTERVAL 1 HOUR); -- 1時間後
SELECT DATE_ADD(NOW(), INTERVAL 30 MINUTE); -- 30分後
SELECT DATE_ADD(NOW(), INTERVAL 1 WEEK); -- 1週間後
SELECT DATE_ADD(NOW(), INTERVAL 3 MONTH); -- 3ヶ月後
SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR); -- 1年後
ポイント
- NOW()、CURDATE()は動的な値(実行時の現在時刻)
- INTERVAL を使って柔軟に日付計算
- DATEDIFF で期間計算が簡単にできる
関数を活用すれば、日付を柔軟に扱えます。
次は、日付を条件に使った検索例を見てみましょう。
日付で条件を指定してデータを抽出しよう

特定の日付でデータを抽出
-- 今日の注文だけを取得
SELECT * FROM orders
WHERE DATE(order_date) = CURDATE();
-- 2025年6月3日の注文だけを取得
SELECT * FROM orders
WHERE DATE(order_date) = '2025-06-03';
-- 今月の注文を取得
SELECT * FROM orders
WHERE YEAR(order_date) = YEAR(NOW())
AND MONTH(order_date) = MONTH(NOW());
期間を指定してデータを抽出
-- 直近7日間の注文
SELECT * FROM orders
WHERE order_date >= DATE_SUB(NOW(), INTERVAL 7 DAY);
-- 先月の注文
SELECT * FROM orders
WHERE order_date >= DATE_SUB(DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY), INTERVAL 1 MONTH)
AND order_date < DATE_SUB(CURDATE(), INTERVAL DAY(CURDATE())-1 DAY);
-- より簡単な先月の書き方
SELECT * FROM orders
WHERE YEAR(order_date) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH))
AND MONTH(order_date) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH));
範囲指定での抽出
-- 2025年1月1日から6月30日までの注文
SELECT * FROM orders
WHERE order_date BETWEEN '2025-01-01' AND '2025-06-30 23:59:59';
-- 3ヶ月以内の注文
SELECT * FROM orders
WHERE order_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH);
-- 1年以上前の古いデータ
SELECT * FROM orders
WHERE order_date < DATE_SUB(NOW(), INTERVAL 1 YEAR);
時刻を含む条件指定
-- 今日の午前中の注文
SELECT * FROM orders
WHERE DATE(order_date) = CURDATE()
AND TIME(order_date) < '12:00:00';
-- 営業時間内(9:00-18:00)の注文
SELECT * FROM orders
WHERE TIME(order_date) BETWEEN '09:00:00' AND '18:00:00';
-- 週末の注文
SELECT * FROM orders
WHERE DAYOFWEEK(order_date) IN (1, 7); -- 1=日曜日, 7=土曜日
便利な条件指定のパターン
-- 今年のデータ
SELECT * FROM orders WHERE YEAR(order_date) = YEAR(NOW());
-- 今四半期のデータ
SELECT * FROM orders
WHERE QUARTER(order_date) = QUARTER(NOW())
AND YEAR(order_date) = YEAR(NOW());
-- 誕生日が今月の顧客
SELECT * FROM customers
WHERE MONTH(birthday) = MONTH(NOW());
ポイント
- DATE()関数で日付部分のみを比較
- BETWEEN で範囲指定が簡単
- INTERVAL を使った相対的な期間指定が便利
日付条件を活用すれば、動的なデータ抽出も可能になります。次は、日付による並び替えやグループ化を紹介します。
ORDER BYとGROUP BYで日付を活用しよう
日付での並び替え(ORDER BY)
-- 注文日の新しい順に並べる
SELECT customer_name, order_date FROM orders
ORDER BY order_date DESC;
-- 注文日の古い順に並べる
SELECT customer_name, order_date FROM orders
ORDER BY order_date ASC;
-- 複数の条件で並び替え(日付→時刻順)
SELECT customer_name, order_date FROM orders
ORDER BY DATE(order_date) DESC, TIME(order_date) ASC;
日付でのグループ化(GROUP BY)
日別の集計
-- 日別の注文件数
SELECT
DATE(order_date) AS order_day,
COUNT(*) AS order_count
FROM orders
GROUP BY DATE(order_date)
ORDER BY order_day DESC;
月別の集計
-- 月別の注文件数
SELECT
DATE_FORMAT(order_date, '%Y-%m') AS order_month,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY order_month DESC;
-- より読みやすい月別集計
SELECT
YEAR(order_date) AS year,
MONTH(order_date) AS month,
COUNT(*) AS order_count
FROM orders
GROUP BY YEAR(order_date), MONTH(order_date)
ORDER BY year DESC, month DESC;
曜日別の集計
-- 曜日別の注文件数
SELECT
CASE DAYOFWEEK(order_date)
WHEN 1 THEN '日曜日'
WHEN 2 THEN '月曜日'
WHEN 3 THEN '火曜日'
WHEN 4 THEN '水曜日'
WHEN 5 THEN '木曜日'
WHEN 6 THEN '金曜日'
WHEN 7 THEN '土曜日'
END AS day_of_week,
COUNT(*) AS order_count
FROM orders
GROUP BY DAYOFWEEK(order_date)
ORDER BY DAYOFWEEK(order_date);
時間帯別の集計
-- 時間帯別の注文件数
SELECT
HOUR(order_date) AS hour,
COUNT(*) AS order_count
FROM orders
GROUP BY HOUR(order_date)
ORDER BY hour;
-- 時間帯をグループ化
SELECT
CASE
WHEN HOUR(order_date) BETWEEN 6 AND 11 THEN '午前'
WHEN HOUR(order_date) BETWEEN 12 AND 17 THEN '午後'
WHEN HOUR(order_date) BETWEEN 18 AND 23 THEN '夜'
ELSE '深夜・早朝'
END AS time_period,
COUNT(*) AS order_count
FROM orders
GROUP BY time_period
ORDER BY time_period;
結果のイメージ(月別集計)
order_month | order_count | total_amount
------------|-------------|-------------
2025-06 | 45 | 125000
2025-05 | 38 | 98000
2025-04 | 52 | 142000
応用的な集計例
-- 四半期別の売上推移
SELECT
YEAR(order_date) AS year,
QUARTER(order_date) AS quarter,
COUNT(*) AS order_count,
AVG(amount) AS avg_amount
FROM orders
GROUP BY YEAR(order_date), QUARTER(order_date)
ORDER BY year DESC, quarter DESC;
-- 週別の売上(月曜日始まり)
SELECT
DATE_SUB(order_date, INTERVAL (DAYOFWEEK(order_date) + 5) % 7 DAY) AS week_start,
COUNT(*) AS order_count
FROM orders
GROUP BY week_start
ORDER BY week_start DESC;
ポイント
- GROUP BY で様々な時間単位での集計が可能
- DATE_FORMAT で柔軟な日付表示
- CASE文で読みやすい表示に変換
データの傾向分析や可視化に日付集計は不可欠です。
最後に、日付フォーマットの変換方法も見てみましょう。
日付フォーマットを自由に変換しよう

MySQL での日付フォーマット
DATE_FORMAT()
関数を使って、日付の表示形式を自由に変えられます。
よく使うフォーマット指定子
指定子 | 意味 | 例 |
---|---|---|
%Y | 4桁の年 | 2025 |
%y | 2桁の年 | 25 |
%m | 2桁の月(01-12) | 06 |
%c | 月(1-12) | 6 |
%d | 2桁の日(01-31) | 03 |
%e | 日(1-31) | 3 |
%H | 24時間形式の時(00-23) | 15 |
%h | 12時間形式の時(01-12) | 03 |
%i | 分(00-59) | 45 |
%s | 秒(00-59) | 30 |
%W | 曜日名 | Tuesday |
%w | 曜日番号(0=日曜日) | 2 |
実際の使用例
-- 基本的なフォーマット
SELECT DATE_FORMAT(order_date, '%Y/%m/%d') AS japanese_date
FROM orders;
-- 結果例:2025/06/03
-- 時刻も含めたフォーマット
SELECT DATE_FORMAT(order_date, '%Y年%m月%d日 %H時%i分') AS full_datetime
FROM orders;
-- 結果例:2025年06月03日 15時45分
-- 曜日を含むフォーマット
SELECT DATE_FORMAT(order_date, '%Y/%m/%d (%W)') AS date_with_day
FROM orders;
-- 結果例:2025/06/03 (Tuesday)
-- 12時間形式の時刻
SELECT DATE_FORMAT(order_date, '%Y/%m/%d %h:%i %p') AS twelve_hour
FROM orders;
-- 結果例:2025/06/03 03:45 PM
PostgreSQL での日付フォーマット
TO_CHAR()
関数を使用します。
よく使うフォーマット指定子
指定子 | 意味 | 例 |
---|---|---|
YYYY | 4桁の年 | 2025 |
YY | 2桁の年 | 25 |
MM | 2桁の月 | 06 |
DD | 2桁の日 | 03 |
HH24 | 24時間形式の時 | 15 |
HH12 | 12時間形式の時 | 03 |
MI | 分 | 45 |
SS | 秒 | 30 |
DAY | 曜日名(フル) | TUESDAY |
DY | 曜日名(省略) | TUE |
実際の使用例
-- PostgreSQL の例
SELECT TO_CHAR(order_date, 'YYYY/MM/DD') AS formatted_date
FROM orders;
-- 結果例:2025/06/03
SELECT TO_CHAR(order_date, 'YYYY年MM月DD日 HH24:MI') AS japanese_datetime
FROM orders;
-- 結果例:2025年06月03日 15:45
実用的なフォーマット例
-- レポート用の見やすい日付
SELECT
customer_name,
DATE_FORMAT(order_date, '%Y年%m月%d日') AS 注文日,
DATE_FORMAT(order_date, '%H:%i') AS 注文時刻
FROM orders;
-- CSV出力用の形式
SELECT
customer_name,
DATE_FORMAT(order_date, '%Y-%m-%d %H:%i:%s') AS order_datetime
FROM orders;
-- 月次レポート用
SELECT
DATE_FORMAT(order_date, '%Y年%m月') AS 対象月,
COUNT(*) AS 注文件数
FROM orders
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY 対象月 DESC;
文字列から日付への変換
-- 文字列をDATE型に変換
SELECT STR_TO_DATE('2025-06-03', '%Y-%m-%d') AS converted_date;
-- 様々な形式の文字列を変換
SELECT STR_TO_DATE('2025年6月3日', '%Y年%m月%d日') AS japanese_format;
SELECT STR_TO_DATE('06/03/2025', '%m/%d/%Y') AS us_format;
ポイント
- データベースごとに関数名が異なる
- フォーマット指定子を覚えると表示を自由に制御可能
- レポート出力時には読みやすい形式に変換
- 文字列からの変換も可能
フォーマット変換を使えば、ユーザーに見せる日付もわかりやすく整形できます。
まとめ
SQLでの日付・時刻の扱いは、実務で欠かせない技術です。
覚えるべきポイント
- データ型の理解:DATE、TIME、DATETIME、TIMESTAMPの使い分け
- 基本関数:NOW()、CURDATE()、DATE_ADD()、DATEDIFF()など
- 条件指定:WHERE句での期間指定や日付比較
- 集計・並び替え:GROUP BYとORDER BYでの日付活用
- フォーマット変換:見やすい表示形式への変換
実務での活用場面
- 売上分析:日別・月別・四半期別の売上推移
- ユーザー分析:登録日、最終ログイン日での分析
- 在庫管理:入荷日、賞味期限での管理
- レポート作成:期間指定での各種集計レポート
よく使われるパターン
-- 今月の売上
SELECT SUM(amount) FROM sales
WHERE MONTH(sale_date) = MONTH(NOW())
AND YEAR(sale_date) = YEAR(NOW());
-- 直近30日のアクティブユーザー
SELECT COUNT(DISTINCT user_id) FROM access_logs
WHERE access_date >= DATE_SUB(NOW(), INTERVAL 30 DAY);
-- 年齢別の顧客分析
SELECT
FLOOR(DATEDIFF(NOW(), birthday) / 365.25) AS age,
COUNT(*) as customer_count
FROM customers
GROUP BY age
ORDER BY age;
コメント