> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL の日付と時刻の関数

> MySQL の日付と時刻の関数のリファレンスガイド: NOW、CURDATE、DATE_FORMAT、DATEDIFF、DATE_ADD、EXTRACT、STR_TO_DATE、UNIX_TIMESTAMP、およびよくある日付操作のパターン。

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

MySQL は日付と時刻の関数を一式提供しています。主に扱う型は、`DATE`（日付のみ）、`TIME`（時刻のみ）、`DATETIME`（日付 + 時刻、タイムゾーンなし）、および `TIMESTAMP`（日付 + 時刻、UTC で格納され、セッションのタイムゾーンで表示される）です。タイムゾーンの扱いの詳細は、[MySQL のタイムスタンプとタイムゾーン](https://villagesql.com/docs/ja/guides/timestamps-timezones.md)を参照してください。

## 現在の日付と時刻の取得

```sql theme={null}
SELECT NOW();            -- '2024-06-15 14:30:00'  (DATETIME, session timezone)
SELECT SYSDATE();        -- same, but evaluated at call time, not statement start
SELECT CURRENT_TIMESTAMP; -- synonym for NOW()

SELECT CURDATE();        -- '2024-06-15'  (DATE only)
SELECT CURTIME();        -- '14:30:00'    (TIME only)
SELECT UTC_TIMESTAMP();  -- '2024-06-15 21:30:00'  (UTC)
```

`NOW()` はステートメントの開始時に 1 回だけ評価されます。同じ INSERT のすべての行が同じタイムスタンプを得ます。`SYSDATE()` は呼び出されるたびに評価されます。

## 日付の書式設定

`DATE_FORMAT` は、書式文字列を使って日付または日時を文字列に変換します。

```sql theme={null}
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d');          -- '2024-06-15'
SELECT DATE_FORMAT(NOW(), '%d/%m/%Y');          -- '15/06/2024'
SELECT DATE_FORMAT(NOW(), '%M %d, %Y');         -- 'June 15, 2024'
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); -- '2024-06-15 14:30:00'
```

よく使う書式指定子:

| 指定子 | 意味 | 例 |
| :- | :- | :- |
| `%Y` | 4 桁の年 | `2024` |
| `%y` | 2 桁の年 | `24` |
| `%m` | 月（01～12） | `06` |
| `%M` | 月の名前 | `June` |
| `%d` | 日（01～31） | `15` |
| `%H` | 時（00～23） | `14` |
| `%i` | 分（00～59） | `30` |
| `%s` | 秒（00～59） | `00` |
| `%W` | 曜日の名前 | `Saturday` |
| `%w` | 曜日（0=日曜日） | `6` |
| `%j` | 年間の通算日（001～366） | `167` |
| `%U` | 週番号（0～53、週は日曜日から始まる） | `24` |

## 文字列から日付への解析

`STR_TO_DATE` は、同じ書式指定子を使って文字列を日付に変換します。

```sql theme={null}
SELECT STR_TO_DATE('15/06/2024', '%d/%m/%Y');         -- '2024-06-15'
SELECT STR_TO_DATE('June 15, 2024', '%M %d, %Y');     -- '2024-06-15'
SELECT STR_TO_DATE('2024-06-15 14:30:00', '%Y-%m-%d %H:%i:%s');  -- DATETIME
```

文字列が書式に一致しない場合は NULL を返します。

## 日付の演算

**DATE\_ADD / DATE\_SUB** — 間隔を加算または減算します。

```sql theme={null}
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY);        -- 7 days from now
SELECT DATE_ADD(NOW(), INTERVAL 3 MONTH);      -- 3 months from now
SELECT DATE_SUB(NOW(), INTERVAL 1 YEAR);       -- 1 year ago
SELECT DATE_ADD('2024-01-31', INTERVAL 1 MONTH); -- '2024-02-29' (end of Feb)
```

間隔の単位: `SECOND`、`MINUTE`、`HOUR`、`DAY`、`WEEK`、`MONTH`、`QUARTER`、`YEAR`。

`+` と `-` 演算子による短縮形:

```sql theme={null}
SELECT NOW() + INTERVAL 1 DAY;
SELECT '2024-06-15' - INTERVAL 1 MONTH;
```

**DATEDIFF** — 2 つの日付の間の日数です。

```sql theme={null}
SELECT DATEDIFF('2024-12-31', '2024-06-15');  -- 199
SELECT DATEDIFF(NOW(), created_at) AS days_old FROM orders;
```

`DATEDIFF` は日数だけを数え、時刻は数えません。時刻を考慮した差分には `TIMESTAMPDIFF` を使います。

```sql theme={null}
SELECT TIMESTAMPDIFF(HOUR, '2024-06-15 08:00', '2024-06-15 14:30');  -- 6
SELECT TIMESTAMPDIFF(MINUTE, created_at, NOW()) AS minutes_ago FROM events;
```

`TIMESTAMPDIFF(unit, from, to)` — `from` が `to` より前に来ることに注意してください。

## 日付の部分の抽出

**EXTRACT / YEAR / MONTH / DAY**:

```sql theme={null}
SELECT YEAR(NOW());     -- 2024
SELECT MONTH(NOW());    -- 6
SELECT DAY(NOW());      -- 15 (same as DAYOFMONTH)
SELECT HOUR(NOW());     -- 14
SELECT MINUTE(NOW());   -- 30

-- EXTRACT uses interval unit names
SELECT EXTRACT(YEAR FROM NOW());        -- 2024
SELECT EXTRACT(HOUR FROM NOW());        -- 14
SELECT EXTRACT(YEAR_MONTH FROM NOW());  -- 202406
```

**DAYOFWEEK / DAYOFYEAR / WEEK**:

```sql theme={null}
SELECT DAYOFWEEK(NOW());   -- 7  (1=Sunday, 7=Saturday)
SELECT WEEKDAY(NOW());     -- 5  (0=Monday, 6=Sunday)
SELECT DAYOFYEAR(NOW());   -- 167
SELECT WEEK(NOW());        -- 23  (default mode 0: week 0–53, Sunday-based; mode 1 gives 24)
SELECT YEARWEEK(NOW());    -- 202423  (default mode)
```

## 期間への切り捨て

データを月、週、または日でグループ化するには、日時を期間の境界に切り捨てます。

```sql theme={null}
-- Group orders by month
SELECT DATE_FORMAT(created_at, '%Y-%m') AS month, COUNT(*) AS orders
FROM orders
GROUP BY month
ORDER BY month;

-- Group by week
SELECT YEARWEEK(created_at) AS week, COUNT(*) AS orders
FROM orders
GROUP BY week;

-- Truncate to start of month
SELECT DATE_FORMAT(NOW(), '%Y-%m-01');  -- '2024-06-01'
```

## Unix タイムスタンプ

```sql theme={null}
SELECT UNIX_TIMESTAMP();                          -- seconds since epoch (session timezone)
SELECT UNIX_TIMESTAMP('2024-06-15 14:30:00');     -- datetime to epoch (session timezone)
SELECT FROM_UNIXTIME(1718451000);                 -- epoch to DATETIME
SELECT FROM_UNIXTIME(1718451000, '%Y-%m-%d');     -- epoch to formatted string
```

## よくあるパターン

過去 30 日間のレコード:

```sql theme={null}
SELECT * FROM orders WHERE created_at >= NOW() - INTERVAL 30 DAY;
```

今月のレコード:

```sql theme={null}
SELECT * FROM orders
WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')
  AND created_at <  DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');
```

生年月日からの年齢:

```sql theme={null}
SELECT TIMESTAMPDIFF(YEAR, birthdate, CURDATE()) AS age FROM users;
```

## よくある質問

#### NOW() と SYSDATE() の違いは何ですか?

`NOW()` は、ステートメントの実行が始まった時点のタイムスタンプを返します。1 つの INSERT または UPDATE のすべての行が同じ値を得ます。`SYSDATE()` は呼び出された瞬間の実際の時計の時刻を返すため、ループで挿入された行は異なる値を得ます。トランザクション内の一貫性が重要な監査タイムスタンプには、ほぼ常に `NOW()` が正しい選択です。

#### INTERVAL 1 MONTH を指定した DATE\_ADD が月末で奇妙に振る舞うのはなぜですか?

MySQL は最後の有効な日に丸めます。`DATE_ADD('2024-01-31', INTERVAL 1 MONTH)` は `2024-02-29`（うるう年）または `2024-02-28` を返します。これは想定どおりの動作です。「2 月 31 日」は存在しません。予測可能な月の演算が必要な場合は、先に月の初めに切り捨ててください。

## トラブルシューティング

| 問題 | 解決策 |
| :- | :- |
| `STR_TO_DATE` が NULL を返す | 書式文字列が入力に一致していません。各書式指定子が対応する入力文字に一致することを確認します |
| 同じ日付のタイムスタンプに対して `DATEDIFF` が 0 を返す | `DATEDIFF` は時刻の部分を無視します。同じ暦日の 2 行は 0 を返します |
| 日付の比較が、その日の終わりの行を取りこぼす | `WHERE created_at <= '2024-06-15'` はその日の午前 0 時で止まります。その日全体を含めるには `< '2024-06-16'` を使います |
| `TIMESTAMPDIFF` が予期しない負の値を返す | 引数の順序が誤っています。`TIMESTAMPDIFF(unit, from, to)` であり、`(unit, to, from)` ではありません |
| `WEEK()` が予想と異なる数値を返す | 週番号のモード（日曜日始まりか月曜日始まりか）が影響します。ISO 8601 の週番号には `YEARWEEK(date, 3)` を使います |

## 関連項目

* [MySQL のタイムスタンプとタイムゾーン](https://villagesql.com/docs/ja/guides/timestamps-timezones.md) — 日付関数が操作する格納型
* [MySQL の BETWEEN](https://villagesql.com/docs/ja/tutorial/between.md) — 日付の範囲を `>=` と `<` で書くほうが安全な理由


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.