MySQLの日付関数まとめ:DATE_ADD・DATEDIFFの使い方

a colorful toy on a table SQL

MySQLを使っていると、日付の加算や差分の計算、表示形式の変換は日常的に必要になります。「3日後の日付を求めたい」「契約開始日から今日まで何日経ったか調べたい」「日付を〝2026年06月07日〟と整形したい」—こうした処理はすべて、MySQLの標準関数で完結します。本記事では NOW・CURDATE・DATE_ADD・DATE_SUB・DATEDIFF・TIMESTAMPDIFF・DATE_FORMAT・LAST_DAY・DAYOFWEEK を用途別に整理し、月末計算や曜日取得といった実務パターンもあわせて解説します。

このシナリオで考える

以下の注文テーブル orders を例に進めます。

CREATE TABLE orders (
  order_id     INT          PRIMARY KEY AUTO_INCREMENT,
  customer     VARCHAR(50)  NOT NULL,
  ordered_at   DATE         NOT NULL,
  delivered_at DATE
);

INSERT INTO orders (customer, ordered_at, delivered_at) VALUES
  ('田中', '2026-05-01', '2026-05-05'),
  ('佐藤', '2026-05-15', '2026-05-20'),
  ('鈴木', '2026-06-01', NULL),
  ('高橋', '2026-06-03', NULL);

ordered_at が注文日、delivered_at が配送完了日です。NULL は未配送を意味します。

現在日時を取得する:NOW・CURDATE・CURTIME

まず基本の「今を取得する」関数から押さえます。

関数 戻り値の型 例(2026-06-07 10:30:00 の場合)
NOW() DATETIME 2026-06-07 10:30:00
CURDATE() DATE 2026-06-07
CURTIME() TIME 10:30:00

日付のみが欲しい場面では CURDATE() を使うのが正確です。NOW() をそのまま DATE 型カラムと比較すると、時刻部分が余分になります。

-- 今日注文された件数を調べる
SELECT COUNT(*) AS today_orders
FROM orders
WHERE ordered_at = CURDATE();

NOW() との違いで覚えておきたいのが SYSDATE() です。NOW() はクエリ実行開始時の時刻を返しますが、SYSDATE() は呼び出した瞬間の時刻を返します。通常のクエリでは差がありませんが、ストアドプロシージャ内のループ処理では挙動が変わります。混乱を避けるために NOW() を使うのが安全です。

日付を加算・減算する:DATE_ADD・DATE_SUB

日付に「〇日後」「〇ヵ月前」を計算するには DATE_ADD / DATE_SUB を使います。構文は次のとおりです。

DATE_ADD(date, INTERVAL value unit)
DATE_SUB(date, INTERVAL value unit)

よく使う unit(間隔の単位)をまとめます。

unit 意味 記述例
DAY INTERVAL 7 DAY
WEEK INTERVAL 2 WEEK
MONTH INTERVAL 1 MONTH
YEAR INTERVAL 1 YEAR
HOUR 時間 INTERVAL 3 HOUR
MINUTE INTERVAL 30 MINUTE

注文日から7日後の「期待配送日」を計算する例です。

SELECT
  customer,
  ordered_at,
  DATE_ADD(ordered_at, INTERVAL 7 DAY) AS expected_delivery
FROM orders;
+----------+------------+-------------------+
| customer | ordered_at | expected_delivery |
+----------+------------+-------------------+
| 田中     | 2026-05-01 | 2026-05-08        |
| 佐藤     | 2026-05-15 | 2026-05-22        |
| 鈴木     | 2026-06-01 | 2026-06-08        |
| 高橋     | 2026-06-03 | 2026-06-10        |
+----------+------------+-------------------+

負の INTERVAL を指定すると DATE_SUB と同じ意味になります。DATE_ADD(date, INTERVAL -7 DAY)DATE_SUB(date, INTERVAL 7 DAY) は等価です。引き算には DATE_SUB を使うと読みやすくなります。

日付の差分を求める:DATEDIFFとTIMESTAMPDIFF

2つの日付の間隔を求める関数は2種類あります。用途に応じて使い分けてください。

DATEDIFF:日数のみを返す

DATEDIFF(expr1, expr2)  -- expr1 - expr2 の日数を整数で返す

配送日数(注文日から配送完了日まで)を計算する例です。

SELECT
  customer,
  ordered_at,
  delivered_at,
  DATEDIFF(delivered_at, ordered_at) AS delivery_days
FROM orders
WHERE delivered_at IS NOT NULL;
+----------+------------+--------------+---------------+
| customer | ordered_at | delivered_at | delivery_days |
+----------+------------+--------------+---------------+
| 田中     | 2026-05-01 | 2026-05-05   |             4 |
| 佐藤     | 2026-05-15 | 2026-05-20   |             5 |
+----------+------------+--------------+---------------+

引数の順序は (新しい日付, 古い日付) が正の値を返します。逆にすると負の値になるので注意してください。

TIMESTAMPDIFF:単位を指定できる

「〇ヵ月差」「〇時間差」を求めたい場合は TIMESTAMPDIFF を使います。

TIMESTAMPDIFF(unit, datetime_expr1, datetime_expr2)
-- datetime_expr2 - datetime_expr1 を unit 単位の整数で返す

注文日から今日まで何ヵ月経過したかを求める例です。

SELECT
  customer,
  ordered_at,
  TIMESTAMPDIFF(MONTH, ordered_at, CURDATE()) AS months_since_order
FROM orders;
+----------+------------+--------------------+
| customer | ordered_at | months_since_order |
+----------+------------+--------------------+
| 田中     | 2026-05-01 |                  1 |
| 佐藤     | 2026-05-15 |                  0 |
| 鈴木     | 2026-06-01 |                  0 |
| 高橋     | 2026-06-03 |                  0 |
+----------+------------+--------------------+

TIMESTAMPDIFF の引数順序は (単位, 古い日付, 新しい日付) で正の値を返します。DATEDIFF と引数の順序が逆なので、混用するときは特に注意してください。

日付を好きな形式に変換する:DATE_FORMAT

日付の表示形式を自由に変えるには DATE_FORMAT を使います。

DATE_FORMAT(date, format)

よく使うフォーマット指定子を表にまとめます。

指定子 意味 例(2026-06-07 の場合)
%Y 4桁の年 2026
%y 2桁の年 26
%m 2桁の月(01〜12) 06
%c 月(1〜12、ゼロ埋めなし) 6
%d 2桁の日(01〜31) 07
%e 日(1〜31、ゼロ埋めなし) 7
%H 時(00〜23) 10
%i 分(00〜59) 30
%s 秒(00〜59) 00
%W 曜日(英語フル) Sunday
%w 曜日番号(0=日曜〜6=土曜) 0

日本語表記に整形する例です。

SELECT
  customer,
  DATE_FORMAT(ordered_at, '%Y年%m月%d日') AS ordered_jp
FROM orders;
+----------+------------------+
| customer | ordered_jp       |
+----------+------------------+
| 田中     | 2026年05月01日   |
| 佐藤     | 2026年05月15日   |
| 鈴木     | 2026年06月01日   |
| 高橋     | 2026年06月03日   |
+----------+------------------+

年月のみでまとめて集計したいときは DATE_FORMAT(ordered_at, '%Y-%m') を GROUP BY に使うのが定番です。

月末・曜日を扱う:LAST_DAY・DAYOFWEEK・DAYNAME

実務でよく使うが見落としがちな関数を3つ紹介します。

LAST_DAY:月の最終日を求める

LAST_DAY(date) は、その月の最終日付を返します。月末締めの処理で重宝します。

SELECT
  LAST_DAY('2026-02-01') AS feb_end,        -- うるう年も自動判定
  LAST_DAY(CURDATE())    AS this_month_end;
+------------+----------------+
| feb_end    | this_month_end |
+------------+----------------+
| 2026-02-28 | 2026-06-30     |
+------------+----------------+

「今月の最終日を動的に取得したい」という場面で特に活躍します。うるう年の判定も自動なので、手動で計算する必要はありません。

DAYOFWEEK・DAYNAME:曜日を取得する

DAYOFWEEK(date) は曜日番号(1=日曜、2=月曜…7=土曜)を返します。DAYNAME(date) は英語の曜日名を返します。

SELECT
  ordered_at,
  DAYOFWEEK(ordered_at) AS day_num,   -- 1=日 〜 7=土
  DAYNAME(ordered_at)   AS day_name
FROM orders;
+------------+---------+-----------+
| ordered_at | day_num | day_name  |
+------------+---------+-----------+
| 2026-05-01 |       6 | Friday    |
| 2026-05-15 |       6 | Friday    |
| 2026-06-01 |       2 | Monday    |
| 2026-06-03 |       4 | Wednesday |
+------------+---------+-----------+

「土日を除外して平日だけ集計したい」「月曜始まりでカレンダー集計したい」といった場面で使います。DAYOFWEEK の番号は 1 が日曜始まりなので、月曜を 1 としたい場合は MOD(DAYOFWEEK(date) + 5, 7) + 1 で変換できます。

よくある落とし穴 / 注意点

文字列と DATE 型の暗黙変換に注意する。MySQL は '2026-06-07' のような文字列を DATE 型に自動変換しますが、'20260607''2026/06/07' はフォーマットによっては変換に失敗します。確実に変換するには STR_TO_DATE('2026/06/07', '%Y/%m/%d') を使ってください。

DATEDIFFとTIMESTAMPDIFFの引数順序が逆。DATEDIFF(a, b)a - b の日数を返しますが、TIMESTAMPDIFF(unit, a, b)b - a を返します。2つを混用するときは引数の順を確認してください。

DATE_ADDで月を加算するとき、月末の扱いに注意する。DATE_ADD('2026-01-31', INTERVAL 1 MONTH)2026-02-28 になります(2月が28日しかないため)。「3ヵ月後の同日」を求める処理で意図しない結果になることがあります。

タイムゾーンのずれに注意する。NOW()CURDATE() は MySQL サーバーのタイムゾーン設定に従います。サーバーが UTC で動いている場合、日本時間と9時間ずれます。CONVERT_TZ(NOW(), '+00:00', '+09:00') で変換するか、SELECT @@time_zone; でサーバー設定を確認してください。

まとめ

MySQL の日付関数は、取得・計算・差分・整形の4つに分けると把握しやすくなります。NOW/CURDATE で現在値を取り、DATE_ADD/DATE_SUB で加減算し、DATEDIFF/TIMESTAMPDIFF で差分を求め、DATE_FORMAT で表示を整える—この4パターンを押さえれば、実務の日付処理はほぼカバーできます。引数の順序やタイムゾーンの落とし穴だけ意識しながら使ってみてください。

参考リンク

アイキャッチ画像: Photo by Shubham Dhage on Unsplash

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