🧚 お知らせ!Beekeeper Studio は高速でモダンなオープンソースのデータベース GUI です ダウンロード
2026年1月13日 著者: Matthew Rathbone

DATEDIFF は 2 つの日付の間の日数、月数などの単位数を返します。データベースごとに方法が異なるため、PostgreSQL、MySQL、SQLite、SQL Server の例を紹介します。

DATEDIFF の使い方

DATEDIFF は開始日から終了日までの日数、月数、年数などを数えます。以下は SQL Server 版で、一般に DATEDIFF と言えばこれを指します:

DATEDIFF(unit, start_date, end_date)
SELECT DATEDIFF(day, '2026-01-01', '2026-03-15');
-- Output: 73

SELECT DATEDIFF(month, '2026-01-01', '2026-03-15');
-- Output: 2

SELECT DATEDIFF(day, '2026-03-15', '2026-01-01');
-- Output: -73

単位には year、quarter、month、week、day、hour、minute、second またはそれより小さい単位を指定できます。終了日が開始日より前の場合、結果は負の値になります。

列を指定すると、行ごとに差分が得られます:

-- Input: orders
-- order_id | order_date | ship_date
-- ---------+------------+-----------
-- 1001     | 2026-02-02 | 2026-02-04
-- 1002     | 2026-02-03 | 2026-02-10
-- 1003     | 2026-02-27 | 2026-03-02
-- 1004     | 2026-03-05 | NULL

SELECT
  order_id,
  order_date,
  ship_date,
  DATEDIFF(day, order_date, ship_date) AS fulfillment_days
FROM orders;

-- Output:
-- order_id | order_date | ship_date  | fulfillment_days
-- ---------+------------+------------+-----------------
-- 1001     | 2026-02-02 | 2026-02-04 | 2
-- 1002     | 2026-02-03 | 2026-02-10 | 7
-- 1003     | 2026-02-27 | 2026-03-02 | 3
-- 1004     | 2026-03-05 | NULL       | NULL

知っておくべきルール

  • 数えるのは境界であり、完全な単位ではありません。 DATEDIFF(month, ...) は 2 つの日付の間にある月の境界を数えるため、たった 1 日でも 1 か月、あるいは 1 年として数えられることがあります:
SELECT DATEDIFF(month, '2026-01-31', '2026-02-01');
-- Output: 1

SELECT DATEDIFF(year, '2025-12-31', '2026-01-01');
-- Output: 1
  • NULL を渡すと NULL が返ります。 どちらかの日付が NULL の場合、上の注文 1004 のように結果も NULL になります。デフォルト値が必要な場合は COALESCE() で囲みます。

別の構文

MySQL の DATEDIFF は引数が 2 つで、日数のみを数え、終了日を先に指定します。その他の単位には TIMESTAMPDIFF を使います。こちらは開始日を先に指定し、完全な単位で数えます:

SELECT DATEDIFF('2026-03-15', '2026-01-01');
-- Output: 73

SELECT TIMESTAMPDIFF(MONTH, '2026-01-01', '2026-03-15');
-- Output: 2

PostgreSQL には DATEDIFF がありません。日付から日付を引くと日数が得られます。より大きな単位には、AGE()(後の日付を先に指定)が年・月・日の interval を返し、EXTRACT でそこから完全な単位を取り出せます:

SELECT DATE '2026-03-15' - DATE '2026-01-01';
-- Output: 73

SELECT AGE('2026-03-15', '2026-01-01');
-- Output: 2 mons 14 days

SELECT EXTRACT(YEAR FROM AGE('2026-03-15', '2026-01-01')) * 12
     + EXTRACT(MONTH FROM AGE('2026-03-15', '2026-01-01'));
-- Output: 2

SQLite にも DATEDIFF はありません。julianday() は日付を日数の数値に変換するので、2 つを引き算すれば差分が得られます。CAST(... AS INTEGER) で小数部分を切り捨てます。月や年の単位はないため、近似値を得るには 30 または 365 で割ります:

SELECT julianday('2026-03-15') - julianday('2026-01-01');
-- Output: 73.0

SELECT CAST((julianday('2026-03-15') - julianday('2026-01-01')) / 30 AS INTEGER);
-- Output: 2

-- The time of day counts: 8 p.m. to 8 a.m. is half a day.
-- Wrap each value in date() to count calendar days instead.
SELECT julianday('2026-03-16 08:00') - julianday('2026-03-15 20:00');
-- Output: 0.5

-- A date it can't read gives NULL, so store dates as YYYY-MM-DD
SELECT julianday('03/15/2026');
-- Output: NULL

DATEDIFF はどんなときに使う?

日付の差に関する問いの多くは、次の 4 つのいずれかに当てはまります。

かかった時間を測る

終了日から開始日を引いて期間を求めます。注文の発送にかかった日数、プロジェクトの実施週数、サポート通話の分数などです。

超過日数や残り日数を数える

期限を今日や固定のレポート日と比較して、どれだけ遅れているか、あとどれだけ残っているかを確認します。結果の符号で絞り込めば、どちらか一方だけを残せます。

経過期間を月や年で表す

アカウントの経過期間、顧客の継続期間、勤続年数などには日より大きな単位が必要です。データベースに月や年の単位があればそれを使い、SQLite では日数を割ります。

ある日付の前後の範囲にある行を探す

差分の絶対値をとると、ある日付の前後一定日数以内にある行を見つけられます。ローンチ前後のイベントや、障害発生前後のログインなどです。

DATEDIFF の実例

サポートチケットを SLA と照合する

各チケットは 3 日以内に解決する必要があります。それぞれにかかった日数を数え、違反にフラグを立てます(SQLite):

-- Input: support_tickets
-- ticket_id | created_at | resolved_at
-- ----------+------------+------------
-- 301       | 2026-03-02 | 2026-03-03
-- 302       | 2026-03-04 | 2026-03-07
-- 303       | 2026-03-05 | 2026-03-10

SELECT
  ticket_id,
  created_at,
  resolved_at,
  CAST(julianday(resolved_at) - julianday(created_at) AS INTEGER) AS resolution_days,
  CASE
    WHEN julianday(resolved_at) - julianday(created_at) <= 3 THEN 'Within SLA'
    ELSE 'SLA Breach'
  END AS sla_status
FROM support_tickets;

-- Output:
-- ticket_id | created_at | resolved_at | resolution_days | sla_status
-- ----------+------------+-------------+-----------------+-----------
-- 301       | 2026-03-02 | 2026-03-03  | 1               | Within SLA
-- 302       | 2026-03-04 | 2026-03-07  | 3               | Within SLA
-- 303       | 2026-03-05 | 2026-03-10  | 5               | SLA Breach

期限切れの請求書を一覧表示する

支払期日を過ぎた請求書を、超過日数の多い順に表示します(MySQL):

-- Input: invoices
-- invoice_id | customer      | due_date
-- -----------+---------------+-----------
-- 5001       | Acme Hardware | 2026-08-15
-- 5002       | Lumen Design  | 2026-09-30
-- 5003       | Acme Hardware | 2026-10-01
-- 5004       | Cedar Clinic  | 2026-10-31

SELECT
  invoice_id,
  customer,
  due_date,
  DATEDIFF(CURDATE(), due_date) AS days_overdue
FROM invoices
WHERE due_date < CURDATE()
ORDER BY days_overdue DESC;

-- Output (run on 2026-10-13):
-- invoice_id | customer      | due_date   | days_overdue
-- -----------+---------------+------------+-------------
-- 5001       | Acme Hardware | 2026-08-15 | 59
-- 5002       | Lumen Design  | 2026-09-30 | 13
-- 5003       | Acme Hardware | 2026-10-01 | 12

顧客を利用期間でグループ化する

顧客を満年数での継続期間によってランク分けします(PostgreSQL):

-- Input: customers
-- customer_name     | signup_date
-- ------------------+------------
-- Northwind Traders | 2022-11-05
-- Bluebird Bakery   | 2025-06-20
-- Fjord Outfitters  | 2025-12-20
-- Kestrel Labs      | 2026-03-02

SELECT
  customer_name,
  signup_date,
  EXTRACT(YEAR FROM AGE(CURRENT_DATE, signup_date)) AS years_with_us,
  CASE
    WHEN AGE(CURRENT_DATE, signup_date) < INTERVAL '1 year' THEN 'New'
    WHEN AGE(CURRENT_DATE, signup_date) < INTERVAL '2 years' THEN 'Established'
    ELSE 'Loyal'
  END AS customer_tier
FROM customers;

-- Output (run on 2026-10-13):
-- customer_name     | signup_date | years_with_us | customer_tier
-- ------------------+-------------+---------------+--------------
-- Northwind Traders | 2022-11-05  | 3             | Loyal
-- Bluebird Bakery   | 2025-06-20  | 1             | Established
-- Fjord Outfitters  | 2025-12-20  | 0             | New
-- Kestrel Labs      | 2026-03-02  | 0             | New

更新時期が近いサブスクリプションを探す

今後 30 日以内に終了するサブスクリプションを、残り日数とともに一覧表示します(SQL Server)。WHERE 句では subscription_end を DATEDIFF で囲まずに日付範囲と比較しているため、列のインデックスを引き続き利用できます。

-- Input: subscriptions
-- customer_name    | subscription_end
-- -----------------+-----------------
-- Harbor Dental    | 2026-10-09
-- Maple Yoga       | 2026-10-20
-- Orbit Analytics  | 2026-11-07
-- Pinecrest Realty | 2027-01-15

SELECT
  customer_name,
  subscription_end,
  DATEDIFF(day, GETDATE(), subscription_end) AS days_remaining
FROM subscriptions
WHERE subscription_end BETWEEN CAST(GETDATE() AS date)
                           AND DATEADD(day, 30, CAST(GETDATE() AS date))
ORDER BY days_remaining;

-- Output (run on 2026-10-13):
-- customer_name   | subscription_end | days_remaining
-- ----------------+------------------+---------------
-- Maple Yoga      | 2026-10-20       | 7
-- Orbit Analytics | 2026-11-07       | 25

DATEDIFF についてさらに学ぶ

このブログの記事:

公式ドキュメント:

Beekeeper Studioは無料のオープンソースのデータベースGUIです

これまで使った中で最高のSQLクエリ&エディタツールです。データベースの管理に必要なものがすべて揃っています。 - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studioは高速で直感的、そして使いやすいツールです。多数のデータベースに対応し、Windows、Mac、Linuxで快適に動作します。

BeekeeperのLinux版は100%フル機能。手抜きも機能の妥協も一切ありません。

Beekeeper Studio 利用者の声

★★★★★
「Beekeeper Studio で以前の SQL ワークフローを完全に置き換えました。高速で直感的で、データベース作業がまた楽しくなりました。」
— Alex K.、データベース開発者
★★★★★
「多くのデータベース GUI を試してきましたが、Beekeeper は機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」
— Sarah M.、フルスタックエンジニア