MySQL の日付・時刻型を使い分ける

MySQL には日付や時刻を扱うための型が複数あり、それぞれ格納できる範囲や挙動が異なります。特に DATETIME と TIMESTAMP の違いは実務で頻繁に問題になるため、正確に理解しておく必要があります。

日付時刻型の一覧

格納内容範囲
DATE日付のみ1000-01-01 〜 9999-12-31
TIME時刻のみ-838:59:59 〜 838:59:59
DATETIME日付+時刻1000-01-01 〜 9999-12-31
TIMESTAMP日付+時刻1970-01-01 〜 2038-01-19
YEAR年のみ1901 〜 2155

DATE はストレージ3バイト、DATETIME は5バイト(MySQL 5.6.4 以降)、TIMESTAMP は4バイトを消費します。

DATETIME と TIMESTAMP の違い

この2つは見た目が似ていますが、内部動作が大きく異なります。

DATETIME

入力された値をそのまま格納します。タイムゾーンの変換は行われません。アプリケーション側でタイムゾーンを管理する設計に向いています。

TIMESTAMP

内部的に UTC に変換して格納し、取得時にセッションのタイムゾーンに変換して返します。サーバーのタイムゾーン設定に依存するため、挙動に注意が必要です。

TIMESTAMP のもうひとつの特徴は、2038年問題があることです。内部的に Unix タイムスタンプ(32ビット整数)で管理しているため、2038年1月19日を超える日付を格納できません。長期間保持するデータには DATETIME を使いましょう。

よくある使い分けパターン

created_at / updated_at

レコードの作成日時・更新日時には DATETIME を使うのが安全です。TIMESTAMP の自動更新機能は便利ですが、2038年問題やタイムゾーン変換の影響を考慮すると、DATETIME のほうが予測しやすい挙動になります。

誕生日や記念日

日付だけで十分な場合は DATE 型を使います。時刻情報が不要なのに DATETIME を使うと、無駄なストレージ消費と「00:00:00」という意味のない時刻が付いてきます。

経過時間や所要時間

作業時間や再生時間のような「時間の長さ」を表す場合は TIME 型が適しています。838時間59分59秒まで格納可能です。

小数秒の対応

MySQL 5.6.4 以降では、DATETIME や TIMESTAMP に小数秒(マイクロ秒まで)を格納できます。

-- 小数秒3桁(ミリ秒)まで格納
CREATE TABLE events (
  id INT AUTO_INCREMENT PRIMARY KEY,
  event_name VARCHAR(100) NOT NULL,
  occurred_at DATETIME(3) NOT NULL
);

-- 挿入例
INSERT INTO events (event_name, occurred_at)
VALUES ('click', '2024-06-15 14:30:00.123');

DATETIME(0) から DATETIME(6) まで指定でき、桁数に応じて追加のストレージ(0〜3バイト)が必要になります。ログやイベント追跡のように高精度な時刻が求められる場面で活用できます。

タイムゾーンを意識した設計

グローバルなサービスでは、すべての日時を UTC で統一して格納し、表示時にユーザーのタイムゾーンに変換するのが一般的な設計パターンです。この方針を取る場合、DATETIME に UTC 値を入れるか、TIMESTAMP の自動変換に任せるかの判断が必要になります。チーム内で方針を統一することが、日時関連のバグを防ぐ最大のポイントです。