MySQLで現在時刻を取得する方法まとめ|NOW・CURRENT_TIMESTAMPの違いとタイムゾーン設定まで完全解説

目次

1. MySQLで現在時刻を取得する最短SQL

MySQLで現在時刻を取得したい場合、まず覚えるべき関数は NOW()CURRENT_TIMESTAMP です。用途別に最短SQLを示します。

1.1 今の日時を取得する(基本)

SELECT NOW();

または

SELECT CURRENT_TIMESTAMP;
  • どちらも 現在の日時(YYYY-MM-DD HH:MM:SS) を返します。

  • 同一クエリ内では「クエリ開始時点」の時刻が固定されます。

用途

  • ログ記録

  • データ作成日時の取得

  • 基準時刻の取得

よくある失敗

  • アプリ側のタイムゾーンとDB側のタイムゾーンが異なり「時刻がずれる」
    SELECT @@session.time_zone; で確認

1.2 今日の日付だけ取得する

SELECT CURDATE();
  • 返却形式:YYYY-MM-DD

  • 型は DATE型(日時ではなく日付のみ)

用途

  • 「今日のデータ」検索

  • 日単位集計

注意点

  • NOW()と違い時刻は含まれません。

  • 期間検索で時刻も必要な場合は NOW() を使う。

1.3 現在の時刻だけ取得する

SELECT CURTIME();
  • 返却形式:HH:MM:SS

  • 型は TIME型(時間のみ)

用途

  • バッチ実行時刻の表示

  • ログの時刻のみ出力

つまずきポイント

  • 日付は含まれないため、日時比較には使えません。

1.4 UTCで現在時刻を取得する(重要)

SELECT UTC_TIMESTAMP();
  • サーバーのタイムゾーンに依存せず、UTC(協定世界時) を返します。

  • グローバルサービスでは推奨される取得方法。

実務での基本方針

  • 保存はUTC

  • 表示時にローカルタイムへ変換

注意点

  • アプリ側が既にUTC変換している場合、二重変換に注意。

1.5 ミリ秒・マイクロ秒を含めて取得する

SELECT NOW(3);  -- ミリ秒(小数点以下3桁)
SELECT NOW(6);  -- マイクロ秒(小数点以下6桁)
  • MySQL 5.6.4以降で使用可能。

  • 高精度ログ・トランザクション監査で利用。

よくある誤解

  • NOW() だけでは小数点以下は取得できません。

  • カラム側も DATETIME(6) など精度指定が必要。

1.6 用途別の最適関数まとめ(迷ったらここ)

用途推奨関数
一般的な現在日時取得NOW()
テーブルのデフォルト値CURRENT_TIMESTAMP
日付だけ必要CURDATE()
時刻だけ必要CURTIME()
UTCで統一管理UTC_TIMESTAMP()
高精度ログNOW(6)

つまずきやすい重要ポイント

  • NOW()CURRENT_TIMESTAMP は実質同義(取得値は同じ)

  • 同一クエリ内では時刻は固定される

  • タイムゾーン設定により表示が変わる

  • マイクロ秒を扱う場合はカラム定義も精度指定が必要

2. NOW() / CURRENT_TIMESTAMP / SYSDATE() の違い

現在時刻を取得する関数は複数ありますが、最も混乱しやすいのが NOW()CURRENT_TIMESTAMPSYSDATE() の違いです。
ここを正確に理解していないと、ログやトランザクション処理で予期しない挙動になります。

2.1 NOW()CURRENT_TIMESTAMP は実質同義

SELECT NOW(), CURRENT_TIMESTAMP;
  • どちらも 現在の日時(DATETIME値) を返します。

  • 同一クエリ内では「クエリ開始時点」の時刻で固定されます。

  • CURRENT_TIMESTAMP は関数呼び出し形式でも使用可能:

SELECT CURRENT_TIMESTAMP();

実務での使い分け

用途推奨
単純な取得NOW()
テーブルのDEFAULTやON UPDATECURRENT_TIMESTAMP

重要ポイント

  • 取得値の意味は同じ。

  • 違いは「構文上の扱い(DEFAULT指定可)」が主。

  • 型の違いではない(誤解しやすい点)。

2.2 SYSDATE() は“評価時点”の時刻を返す

SYSDATE()NOW() に似ていますが、時刻の固定タイミングが異なります。

SELECT NOW(), SLEEP(2), NOW();

結果(例):

2025-02-23 14:00:00
2025-02-23 14:00:00
SELECT SYSDATE(), SLEEP(2), SYSDATE();

結果(例):

2025-02-23 14:00:00
2025-02-23 14:00:02

違いの本質

関数時刻が固定されるタイミング
NOW()クエリ開始時点
SYSDATE()実行評価時点

つまり SYSDATE() は、同一クエリ内でも時間経過で値が変わります。

2.3 トランザクションやレプリケーションでの注意点

NOW() はクエリ開始時に固定されるため、
トランザクション内で一貫した基準時刻を扱う場合に安全です。

一方 SYSDATE() は実行タイミング依存のため、

  • レプリケーション(複製環境)

  • バッチ処理

  • ログ一括処理

では再現性に影響する可能性があります。

原則

  • 基準時刻を固定したい → NOW()

  • 毎回その瞬間の時刻が必要 → SYSDATE()(限定用途)

2.4 補足:CURRENT_DATE / CURRENT_TIME / LOCALTIME

MySQLでは以下も利用できます:

SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
SELECT LOCALTIME;
  • CURRENT_DATECURDATE() と同義

  • CURRENT_TIMECURTIME() と同義

  • LOCALTIMENOW() と同義

つまずきやすい点

  • どれも「見た目の違い」であり、機能差はほぼありません。

  • 可読性を優先し、プロジェクト内で統一するのが安全。

この章の重要まとめ

  • NOW()CURRENT_TIMESTAMP は実質同じ意味。

  • SYSDATE() は評価時刻ベースで挙動が異なる。

  • 基準時刻を固定する処理では NOW() を使うのが基本。

  • DEFAULTやON UPDATEには CURRENT_TIMESTAMP を使用。

3. 現在時刻の表示形式を変える

MySQLで NOW() などを使って取得した現在時刻は、標準では YYYY-MM-DD HH:MM:SS 形式で表示されます。しかし、実務では以下のような要望が頻繁に発生します。

  • 年月日だけ表示したい

  • YYYY/MM/DD 形式にしたい

  • 日本語表記にしたい(例:2025年02月23日)

  • ミリ秒まで表示したい

このときに使用するのが DATE_FORMAT() 関数(日時を任意形式に変換する関数) です。

3.1 DATE_FORMAT() の基本構文

DATE_FORMAT(日時, 'フォーマット文字列')

例:現在時刻を YYYY/MM/DD HH:MM 形式に変換

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d %H:%i');

出力例:

2025/02/23 14:35

よく使う指定子

指定子意味
%Y4桁の年2025
%m2桁の月02
%d2桁の日23
%H24時間表記の時14
%i35
%s50
%fマイクロ秒123456

注意点

  • フォーマット指定子は大文字・小文字で意味が異なる場合がある。

  • %h は12時間表記、%H は24時間表記。

3.2 よくあるフォーマット例(実務で頻出)

1. スラッシュ区切り

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d');

2. 日本語表記

SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日');

3. 秒なし表示

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i');

つまずきやすいポイント

  • 文字列として返るため、数値計算には使えない。

  • 比較や検索には元のDATETIME型を使うべき。

3.3 日付部分・時間部分だけを取り出す方法

フォーマット変換ではなく、型を維持したまま取得する方法もあります。

SELECT DATE(NOW());   -- 日付のみ(DATE型)
SELECT TIME(NOW());   -- 時刻のみ(TIME型)
SELECT YEAR(NOW());   -- 年だけ
SELECT MONTH(NOW());  -- 月だけ
SELECT DAY(NOW());    -- 日だけ

実務での使い分け

目的推奨
表示用整形DATE_FORMAT
計算・比較DATE() / TIME()

3.4 マイクロ秒を含めて表示する

高精度ログが必要な場合:

SELECT NOW(6);

フォーマット指定:

SELECT DATE_FORMAT(NOW(6), '%Y-%m-%d %H:%i:%s.%f');

重要注意点

  • カラム側も DATETIME(6) または TIMESTAMP(6) にしないと精度は保存されない。

  • MySQL 5.6.4未満では使用不可(環境依存)。

よくある失敗

  • DATE_FORMAT() を WHERE句で使い、インデックスが効かなくなる。

    • NG例:

      WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-02-23'
      
    • 推奨:

      WHERE created_at >= '2025-02-23 00:00:00'
        AND created_at <  '2025-02-24 00:00:00'
      
  • 表示用フォーマットをそのまま保存してしまう(検索性能低下)

この章の重要まとめ

  • 表示形式変更は DATE_FORMAT() を使用。

  • 計算・比較は型を保ったまま行う。

  • マイクロ秒を扱う場合はカラム定義も精度指定。

  • WHERE句での関数利用はパフォーマンス低下の原因。

4. 現在時刻を使った日時計算

MySQLでは、現在時刻を基準に「◯時間後」「◯日前」「過去◯日間」といった計算が頻繁に行われます。
実務で最も多いのは 「過去24時間のデータ取得」 です。

日時計算の基本は INTERVAL(時間単位を指定して加減算する構文) です。

4.1 INTERVAL で加算・減算する

1時間後を取得

SELECT NOW() + INTERVAL 1 HOUR;

3日前を取得

SELECT NOW() - INTERVAL 3 DAY;

1ヶ月後を取得

SELECT NOW() + INTERVAL 1 MONTH;

使用できる主な単位

単位意味
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
YEAR

よくある失敗

  • INTERVAL 1 DAYDAY を小文字にしても動くが、チーム内で統一すべき。

  • 月末計算では日数が変動するため、期待通りにならない場合がある(例:1月31日 + 1ヶ月)。

4.2 過去24時間のデータを取得する(最頻出パターン)

SELECT *
FROM users
WHERE created_at >= NOW() - INTERVAL 1 DAY;

意味

  • 「今この瞬間から24時間前まで」を対象にする。

注意点

  • CURDATE() を使うと「今日の0時基準」になるため意味が変わる。

例(今日のデータ):

SELECT *
FROM users
WHERE created_at >= CURDATE();

違いを理解することが重要

書き方意味
NOW() - INTERVAL 1 DAY直近24時間
CURDATE()今日0:00以降

4.3 DATEDIFF() で日数差を求める

SELECT DATEDIFF('2025-03-01', '2025-02-23');

結果:

6
  • 単位は「日」

  • 時刻部分は無視される

注意点

  • 引数の順序で符号が変わる。

  • 時刻単位の差は計算できない。

4.4 TIMESTAMPDIFF() で時間・分・秒を計算

SELECT TIMESTAMPDIFF(HOUR,
                     '2025-02-23 12:00:00',
                     '2025-02-23 18:30:00');

結果:

6

分単位

SELECT TIMESTAMPDIFF(MINUTE,
                     '2025-02-23 12:00:00',
                     '2025-02-23 12:30:00');

秒単位

SELECT TIMESTAMPDIFF(SECOND,
                     '2025-02-23 12:00:00',
                     '2025-02-23 12:00:45');

実務用途

  • セッション滞在時間計算

  • 有効期限チェック

  • タイムアウト判定

4.5 月初・月末の取得(実務でハマるポイント)

今月の1日を取得:

SELECT DATE_FORMAT(NOW(), '%Y-%m-01');

翌月の1日:

SELECT DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');

注意点

  • 月末日は固定値ではない。

  • 期間検索では「>= 開始 AND < 翌月1日」が安全。

よくある失敗まとめ

  • BETWEEN で日付だけ指定して時刻を含め忘れる

  • DATE(created_at) をWHERE句で使いインデックスが無効化

  • 月計算で31日問題にハマる

  • NOW()CURDATE() の違いを誤解

この章の重要まとめ

  • 日時計算は INTERVAL が基本。

  • 直近24時間は NOW() - INTERVAL 1 DAY

  • 日単位は DATEDIFF()、細かい単位は TIMESTAMPDIFF()

  • 月単位の計算は終端条件に注意。

5. 期間検索はBETWEENよりこの書き方が安全

MySQLで期間検索を行う際、多くの初心者が BETWEEN を使用します。しかし、時刻の扱いを誤ると意図しない結果になることが多く、実務ではより安全な書き方が推奨されます。

5.1 BETWEEN の基本と落とし穴

よくある書き方

SELECT *
FROM orders
WHERE order_date BETWEEN '2025-02-01' AND '2025-02-10';

一見問題なさそうですが、これは内部的には次と同じ意味になります:

WHERE order_date >= '2025-02-01 00:00:00'
  AND order_date <= '2025-02-10 00:00:00'

つまり、2月10日の0時以降のデータは含まれません。


5.2 安全な書き方(推奨)

推奨構文

SELECT *
FROM orders
WHERE order_date >= '2025-02-01 00:00:00'
  AND order_date <  '2025-02-11 00:00:00';

ポイント

  • 終端は「翌日0時未満」で指定する

  • <= 23:59:59 よりも安全(マイクロ秒対応)

5.3 今日のデータを取得する正しい方法

NG例:

WHERE DATE(created_at) = CURDATE();

問題点:

  • 列に関数をかけているため、インデックス(索引)が無効化される

  • 大量データでは性能低下

推奨:

WHERE created_at >= CURDATE()
  AND created_at <  CURDATE() + INTERVAL 1 DAY;

これにより:

  • インデックスが効く

  • 高速検索が可能

  • 日付の境界問題を回避

5.4 過去7日・過去30日の安全な書き方

過去7日

WHERE created_at >= NOW() - INTERVAL 7 DAY;

過去30日

WHERE created_at >= NOW() - INTERVAL 30 DAY;

注意点

  • CURDATE() - INTERVAL 7 DAY は「今日0時基準」

  • NOW() - INTERVAL 7 DAY は「現在時刻基準」

  • 要件により使い分ける

5.5 インデックスを効かせるための重要ルール

NG:

WHERE DATE(created_at) = '2025-02-23';

OK:

WHERE created_at >= '2025-02-23 00:00:00'
  AND created_at <  '2025-02-24 00:00:00';

理由:

  • インデックスは「列そのもの」に対して効く

  • 列に関数を適用すると索引が使えない(フルスキャン)

よくある失敗まとめ

  • BETWEEN の終端に時刻を含め忘れる

  • 23:59:59 指定でマイクロ秒を漏らす

  • WHERE句で DATE() を使用し性能低下

  • 基準が「今」なのか「今日0時」なのかを曖昧にする

この章の重要まとめ

  • 期間検索は >= 開始 AND < 終了 が安全。

  • BETWEEN は境界の扱いに注意。

  • インデックスを効かせるため、列に関数をかけない。

  • NOW() 基準と CURDATE() 基準を明確に使い分ける。

6. DEFAULT CURRENT_TIMESTAMP と ON UPDATE(テーブル設計の基本)

データベース設計では、作成日時(created_at)と更新日時(updated_at)を自動管理するのが一般的です。
MySQLでは CURRENT_TIMESTAMP を使うことで、挿入時・更新時に自動で現在時刻を設定できます。

6.1 作成日時を自動セットする(DEFAULT CURRENT_TIMESTAMP)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

動作:

INSERT INTO users (name) VALUES ('Alice');

created_at に現在時刻が自動挿入される。

ポイント

  • CURRENT_TIMESTAMP は DEFAULT に使用可能。

  • NOW() は DEFAULT には直接使用不可。

よくある失敗

created_at DATETIME DEFAULT NOW();  -- エラー

理由:

  • MySQLでは DEFAULT には関数を直接指定できない(例外は CURRENT_TIMESTAMP)。

6.2 更新日時を自動更新する(ON UPDATE)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

動作:

UPDATE users SET name = 'Bob' WHERE id = 1;

updated_at が自動的に現在時刻へ更新。

用途

  • 最終ログイン管理

  • データ更新履歴

  • 監査ログ

6.3 DATETIME と TIMESTAMP の違い(重要)

範囲タイムゾーン影響
DATETIME1000年〜9999年なし
TIMESTAMP1970〜2038年あり

違いの本質

  • TIMESTAMP は内部的にUTCで保存し、表示時にセッションTZへ変換。

  • DATETIME は文字通りその値を保存(変換なし)。

使い分け指針

ケース推奨型
ログ管理TIMESTAMP
将来日付(2038年以降)DATETIME
TZ変換不要の固定値DATETIME

6.4 CURRENT_TIMESTAMP は DATETIME でも使える

MySQL 5.6以降では、DATETIME 型でも DEFAULT および ON UPDATE に CURRENT_TIMESTAMP を指定可能です。

created_at DATETIME DEFAULT CURRENT_TIMESTAMP

注意点

  • 古いMySQLでは制限がある(環境依存)。

  • 精度指定が必要な場合:

DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6)

6.5 NOW() を使いたい場合の代替方法(トリガー)

CREATE TRIGGER set_created_at
BEFORE INSERT ON logs
FOR EACH ROW
SET NEW.created_at = NOW();

用途

  • 複雑な初期値ロジック

  • 条件付き日時設定

注意点

  • トリガーはデバッグが難しい。

  • 不要な場合は避ける。

よくある設計ミス

  • created_atupdated_at の両方に ON UPDATE を付けてしまう

  • DATETIME と TIMESTAMP の挙動を混同

  • タイムゾーン設計を後回しにする

この章の重要まとめ

  • DEFAULT には CURRENT_TIMESTAMP を使う。

  • 更新管理には ON UPDATE CURRENT_TIMESTAMP

  • 型選択は「タイムゾーン影響」と「2038年問題」で判断。

  • 精度が必要なら (6) 指定を忘れない。

7. タイムゾーン設計(UTCで保存してローカル表示する)

現在時刻を扱う際、タイムゾーン(時間帯)設計を誤ると時刻ズレや二重変換が発生します。
実務では原則として「保存はUTC、表示はローカル変換」が安全です。

MySQL timezone architecture storing timestamps in UTC and converting to local time (JST)
図:MySQLにおけるUTC保存とローカルタイム表示の基本構成

7.1 現在のタイムゾーンを確認する

まず、MySQLがどのタイムゾーンで動いているかを確認します。

SELECT @@global.time_zone, @@session.time_zone;
  • @@global.time_zone → サーバー全体の設定

  • @@session.time_zone → 現在の接続セッションの設定

  • SYSTEM の場合はOS設定に依存

よくある問題

  • 本番と開発でOSタイムゾーンが異なる

  • アプリ側でUTC変換しているのにDB側でも変換してしまう

7.2 セッション単位でタイムゾーンを変更する

SET time_zone = 'Asia/Tokyo';

またはUTCへ統一:

SET time_zone = '+00:00';

重要ポイント

  • 接続が切れると元に戻る

  • 接続プール利用時はアプリ設定を確認する

7.3 UTCで保存する理由(実務原則)

推奨方針

  1. データはUTCで保存

  2. 表示時にユーザーのタイムゾーンへ変換

理由:

  • 国際対応が容易

  • 夏時間(DST)問題を回避

  • サーバー移設時の影響を最小化

UTC取得:

SELECT UTC_TIMESTAMP();

7.4 CONVERT_TZ() でタイムゾーン変換

UTC → JST変換例:

SELECT CONVERT_TZ('2025-02-23 05:35:00', '+00:00', '+09:00');

タイムゾーン名指定:

SELECT CONVERT_TZ('2025-02-23 05:35:00', 'UTC', 'Asia/Tokyo');

実務例

SELECT CONVERT_TZ(created_at, 'UTC', 'Asia/Tokyo')
FROM users;

7.5 CONVERT_TZ() が NULL になる原因

もし NULL が返る場合:

  • MySQLのタイムゾーンテーブルが未ロード

  • 指定したタイムゾーン名が存在しない

Linuxでのロード例:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

注意点

  • 本番環境では権限と再起動を確認

  • Docker環境ではzoneinfoが含まれていない場合あり

7.6 サーバー全体のタイムゾーン変更

設定ファイル(my.cnf / my.ini):

[mysqld]
default_time_zone = '+00:00'

再起動後に確認:

SELECT @@global.time_zone;

重要

  • 本番環境での変更は影響範囲を必ず確認

  • 既存データの扱いに注意(表示だけが変わる場合あり)

よくある失敗

  • UTC保存せずローカル保存して後から国際対応

  • アプリ側とDB側で二重変換

  • DATETIME型でTZを意識せず設計

  • テスト環境と本番でTZが異なる

この章の重要まとめ

  • 保存はUTC、表示で変換が基本。

  • UTC_TIMESTAMP() を活用する。

  • CONVERT_TZ() 使用時はTZテーブル確認。

  • タイムゾーンは環境差異を必ず意識する。

8. 実務でそのまま使える現在時刻の活用例

ここでは、MySQLの現在時刻を実際の開発・運用でどのように使うかを具体的なSQL付きで解説します。
そのままコピペして使える形にしています。

8.1 ログ記録に現在時刻を自動で入れる

テーブル作成

CREATE TABLE system_logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    level VARCHAR(50),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

ログ追加

INSERT INTO system_logs (level, message)
VALUES ('ERROR', 'DB接続に失敗しました');

ポイント

  • created_at は自動挿入

  • アプリ側で時刻を渡す必要なし

  • 監査・障害調査で必須設計

よくある失敗

  • アプリ側とDB側で時刻を二重管理

  • タイムゾーン未統一で時刻不整合

8.2 最終ログイン時刻を更新する

テーブル設計

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255),
    last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

ログイン時更新

UPDATE users
SET last_login = NOW()
WHERE id = 1;

注意点

  • ON UPDATE は列が変更されたときのみ発動

  • 変更がないUPDATEでは更新されない場合あり

8.3 バッチ処理で基準時刻を固定する

長時間処理では、基準時刻を固定するのが安全です。

SET @base_time = NOW();

SELECT *
FROM orders
WHERE created_at >= @base_time - INTERVAL 1 DAY;

理由

  • 処理途中で時刻が変わらない

  • 一貫性が保てる

8.4 今日・昨日・直近7日の集計

今日の売上

SELECT SUM(amount)
FROM orders
WHERE created_at >= CURDATE()
  AND created_at <  CURDATE() + INTERVAL 1 DAY;

昨日の売上

SELECT SUM(amount)
FROM orders
WHERE created_at >= CURDATE() - INTERVAL 1 DAY
  AND created_at <  CURDATE();

直近7日

SELECT COUNT(*)
FROM users
WHERE created_at >= NOW() - INTERVAL 7 DAY;

重要

  • WHERE句で列に関数をかけない

  • インデックスを活かす書き方を徹底

8.5 有効期限チェック(セッション・トークン管理)

SELECT *
FROM sessions
WHERE expires_at > NOW();

期限切れ削除

DELETE FROM sessions
WHERE expires_at <= NOW();

よくある失敗

  • CURDATE() を使って時刻を無視してしまう

  • UTC保存しているのにローカルNOW()で比較

8.6 期限が◯時間後のデータ取得

SELECT *
FROM coupons
WHERE expires_at <= NOW() + INTERVAL 1 HOUR;

用途:

  • 有効期限アラート

  • 期限切れ通知

実務で必ず意識すべきこと

  • 取得基準が「今」なのか「今日0時」なのか明確にする

  • インデックスを活かす条件式を書く

  • タイムゾーン設計を最初に決める

  • NOW()UTC_TIMESTAMP() を混在させない

この章の重要まとめ

  • ログ・監査・更新管理には CURRENT_TIMESTAMP

  • 集計は >= AND < 形式で安全に

  • セッション管理は NOW() 比較

  • 基準時刻を固定して一貫性を保つ

9. よくある質問(FAQ)

ここでは、MySQLの現在時刻に関して特に多い疑問と、実務でつまずきやすいポイントを整理します。

9.1 NOW()CURRENT_TIMESTAMP の違いは?

結論:取得値の意味は同じ。

SELECT NOW(), CURRENT_TIMESTAMP;

どちらも現在日時を返します。

違いは主に構文上の扱い

  • CURRENT_TIMESTAMPDEFAULTON UPDATE に使用可能

  • NOW() はDEFAULTには直接使えない

注意

  • 型が違うわけではない

  • 取得値の精度は引数 (6) などで指定可能

9.2 SYSDATE() は使うべき?

SYSDATE() は「評価時点」の時刻を返します。

SELECT SYSDATE(), SLEEP(2), SYSDATE();

同一クエリ内でも値が変わる可能性があります。

使うべき場面

  • その瞬間の実時間を厳密に記録したい場合

避けるべき場面

  • レプリケーション

  • 一貫性が重要なトランザクション処理

基本は NOW() を使えば問題ありません。

9.3 時刻がずれる原因は?

主な原因:

  1. サーバーのタイムゾーン設定

  2. セッションのタイムゾーン設定

  3. アプリ側との二重変換

  4. TIMESTAMP型の自動変換

確認:

SELECT @@global.time_zone, @@session.time_zone;

対策

  • UTC保存を原則にする

  • 表示時のみ変換

  • アプリとDBで方針を統一

9.4 CONVERT_TZ() が NULL になる

原因:

  • タイムゾーンテーブル未ロード

  • タイムゾーン名の誤り

対処:

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

Docker環境では特に要注意。

9.5 BETWEEN で範囲がずれる

NG:

WHERE created_at BETWEEN '2025-02-01' AND '2025-02-10';

安全:

WHERE created_at >= '2025-02-01 00:00:00'
  AND created_at <  '2025-02-11 00:00:00';

理由:

  • 終端時刻問題

  • マイクロ秒漏れ

  • インデックス効率

9.6 DATETIME と TIMESTAMP の選び方は?

  • 国際対応・UTC管理 → TIMESTAMP

  • 2038年以降や固定日時 → DATETIME

設計時に必ず決めること。

9.7 マイクロ秒が保存されない

原因:

  • カラム定義に精度指定なし

修正:

created_at DATETIME(6)

この章の重要まとめ

  • 基本は NOW()CURRENT_TIMESTAMP

  • 期間検索は >= AND <

  • タイムゾーンはUTC保存が安全

  • 型選択と精度指定を忘れない

10. まとめ

本記事では、MySQLで現在時刻を取得・操作・管理する方法を、実務視点で整理しました。
最後に、最低限これだけ理解しておけば安全というポイントをまとめます。

10.1 現在時刻の取得(基本)

  • 一般取得 → NOW()

  • テーブルDEFAULT・更新管理 → CURRENT_TIMESTAMP

  • 日付のみ → CURDATE()

  • 時刻のみ → CURTIME()

  • UTC取得 → UTC_TIMESTAMP()

  • 高精度 → NOW(6)

原則

  • 迷ったら NOW() を使えば問題なし。

  • 設計用途なら CURRENT_TIMESTAMP

10.2 期間検索は「>= AND <」が鉄則

安全な書き方:

WHERE created_at >= '開始'
  AND created_at <  '終了'

理由:

  • 終端時刻の漏れ防止

  • マイクロ秒対応

  • インデックスが効く

NG例

WHERE DATE(created_at) = CURDATE();

列に関数をかけないこと。

10.3 日時計算の基本

  • 加減算 → INTERVAL

  • 日数差 → DATEDIFF()

  • 時間差 → TIMESTAMPDIFF()

基準が「今」か「今日0時」かを常に意識する。

10.4 タイムゾーン設計の原則

  • 保存はUTC

  • 表示時に変換

  • アプリとDBで方針統一

確認コマンド:

SELECT @@global.time_zone, @@session.time_zone;

10.5 テーブル設計のベストプラクティス

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
           ON UPDATE CURRENT_TIMESTAMP
  • 監査・ログ・更新管理は標準装備

  • 精度が必要なら (6) を指定

実務で最も重要な4点

  1. NOW()CURRENT_TIMESTAMP の違いを誤解しない

  2. 期間検索は >= AND <

  3. UTC保存を原則にする

  4. 型選択(DATETIME / TIMESTAMP)を設計段階で決める

MySQLの現在時刻処理は、ログ管理・売上集計・認証管理・バッチ処理など、あらゆる場面の基礎になります。
ここで解説した原則を守れば、時刻ズレ・境界バグ・性能劣化の多くを回避できます。