MySQL 現在時刻の取得方法まとめ|NOW・CURRENT_TIMESTAMP・UTC・ミリ秒・タイムゾーン・DATETIMEとの違い

目次

1. MySQL 現在時刻 取得(結論:最短SQLまとめ)

MySQLで現在時刻を取得したい場合、まず覚えるべきSQLは数個だけです。
検索キーワード「MySQL 現在時刻 取得」に対する最短回答を以下にまとめます。

1.1 MySQL 現在日時:NOW() / CURRENT_TIMESTAMP

現在の「日付+時刻(YYYY-MM-DD HH:MM:SS)」を取得します。

SELECT NOW();
SELECT CURRENT_TIMESTAMP;

実行結果例

2025-02-01 15:30:45
  • NOW()CURRENT_TIMESTAMP は通常同じ結果を返します。
  • どちらも現在の日時を返します。
  • ミリ秒まで取得したい場合は以下を使用します。
SELECT NOW(3);

注意点(よくある失敗)

  • サーバーのタイムゾーン設定に依存します。
  • UTC環境では日本時間ではなくUTCが返る場合があります。
  • クエリ実行中は基本的に同一の時刻が返ります(1ステートメント内で固定)。

1.2 MySQL 現在日付:CURDATE()

日付のみ取得します(時刻なし)。

SELECT CURDATE();

実行結果例

2025-02-01

用途

  • 今日のデータを検索
  • 日付比較(例:本日分のみ抽出)

注意点

  • 返り値は DATE型です。
  • 時刻が必要な処理には使用できません。

1.3 MySQL 現在時刻:CURTIME()

時刻のみ取得します。

SELECT CURTIME();

実行結果例

15:30:45

用途

  • 営業時間判定
  • 時刻帯による条件分岐

注意点

  • 日付情報は含まれません。
  • DATE型カラムとの比較には使えません。

1.4 MySQL UTC 現在時刻:UTC_TIMESTAMP()

タイムゾーン設定に関係なく、UTC(協定世界時)で取得します。

SELECT UTC_TIMESTAMP();

実行結果例

2025-02-01 06:30:45

使うべきケース

  • グローバルサービス
  • ログ保存をUTC統一で行う設計

よくある失敗

  • NOW() と混在させると時刻がズレる
  • アプリ側がJST前提だと9時間差が発生

1.5 MySQL 現在時刻 ミリ秒:NOW(3) / CURRENT_TIMESTAMP(3)

MySQL 5.6以降では小数秒に対応しています。

SELECT NOW(3);
SELECT CURRENT_TIMESTAMP(3);

実行結果例

2025-02-01 15:30:45.123

保存時の注意

カラムも小数秒対応にする必要があります。

DATETIME(3)
TIMESTAMP(3)

未対応カラムに保存すると切り捨てられます。

1.6 目的別チートシート

目的SQL
現在日時SELECT NOW();
UTC取得SELECT UTC_TIMESTAMP();
日付のみSELECT CURDATE();
時刻のみSELECT CURTIME();
ミリ秒取得SELECT NOW(3);

つまずきやすいポイントまとめ

  • タイムゾーン未確認でズレる
  • ミリ秒対応カラムでないのにNOW(3)を使う
  • UTCとローカル時間を混在させる
  • DATETIMEとTIMESTAMPの違いを理解していない
MySQL DATETIME と TIMESTAMP の違いを示した図。TIMESTAMPはUTC変換され、DATETIMEは変換されない。
MySQLのDATETIMEとTIMESTAMPの違い(タイムゾーン変換の有無を比較)

2. MySQL NOW() と CURRENT_TIMESTAMP の違い

NOW()CURRENT_TIMESTAMP は似ていますが、使いどころと挙動の理解不足が不具合の原因になりやすい関数です。ここでは違い・正しい使い分け・落とし穴を整理します。

2.1 どっちを使うべき?(SELECT用途 / DEFAULT用途)

■ SELECTで現在日時を取得する場合

SELECT NOW();
SELECT CURRENT_TIMESTAMP;

通常はどちらも同じ結果を返します。

  • 両者は同義(シノニム)
  • 戻り値は DATETIME 相当
  • タイムゾーン設定の影響を受ける

実務結論

  • 可読性重視 → NOW()
  • 標準SQL寄りに書きたい → CURRENT_TIMESTAMP

■ カラムのデフォルト値に設定する場合

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

ここで重要なのは:

デフォルト値に設定する場合は CURRENT_TIMESTAMP を使うのが一般的

NOW() も使える環境はありますが、MySQLのバージョンやSQLモードによって挙動が異なる場合があります。安全策は CURRENT_TIMESTAMP です。

2.2 DEFAULT / ON UPDATE の正しい使い方

更新日時を自動更新したい場合:

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        ON UPDATE CURRENT_TIMESTAMP
);

動作

  • INSERT時 → created_at / updated_at に現在時刻
  • UPDATE時 → updated_at のみ更新

よくある失敗

  • DATETIME で小数秒精度を合わせていない
  • 複数TIMESTAMP列で古いMySQLバージョン制限に引っかかる(5.6以前は制限あり)

2.3 NOW() と SYSDATE() の違い(重要)

見落とされやすいのが SYSDATE() との違いです。

SELECT NOW(), SYSDATE();

■ 挙動の違い

  • NOW() → クエリ開始時刻で固定
  • SYSDATE() → 呼び出し時点の時刻を返す

例:

SELECT NOW(), SLEEP(3), NOW();

NOW() は同じ値になります。

SELECT SYSDATE(), SLEEP(3), SYSDATE();

SYSDATE() は3秒差が出ます。

2.4 どちらを使うべきか?

関数特徴推奨用途
NOW()クエリ内で固定ログ記録・整合性重視
SYSDATE()呼び出し時刻正確なリアルタイム取得

実務ではNOW()が推奨されることが多い理由

  • トランザクション(複数SQLをまとめて処理する仕組み)内で整合性が取れる
  • レプリケーション環境で安全

2.5 よくある誤解とトラブル

❌ 「NOW() と CURRENT_TIMESTAMP は完全に同じだから何も考えなくていい」

→ デフォルト設定や更新処理では違いが出る場合があります。

❌ 「SYSDATE() のほうが正確だから常に良い」

→ レプリケーション環境では問題を起こす可能性があります。

❌ タイムゾーン未確認

SHOW VARIABLES LIKE '%time_zone%';

確認せずに使用すると時刻ズレが発生します。

2.6 実務ベストプラクティス

  • SELECT取得 → NOW()
  • カラムデフォルト → CURRENT_TIMESTAMP
  • 更新自動化 → ON UPDATE CURRENT_TIMESTAMP
  • 一貫性重視 → NOW() を基本
  • UTC統一設計なら → TIMESTAMP + UTC保存

3. MySQL 現在時刻 フォーマット(DATE_FORMAT / TIME_FORMAT)

MySQLで現在時刻を取得した後、**表示形式を変更したい(フォーマットしたい)**ケースは非常に多いです。
「MySQL 現在時刻 フォーマット」という検索意図に対し、最も重要なのは DATE_FORMAT() の理解です。

3.1 MySQL 日時 フォーマット:DATE_FORMAT(NOW(), …)

基本構文:

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

現在時刻をフォーマットする例:

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

実行結果例

2025-02-01 15:30:45

よく使うフォーマット記号

記号意味
%Y年(4桁)2025
%m月(2桁)02
%d日(2桁)01
%H時(24時間)15
%h時(12時間)03
%i30
%s45
%pAM/PMPM

3.2 日本語形式・12時間形式への変換

■ 日本語形式

SELECT DATE_FORMAT(NOW(), '%Y年%m月%d日 %H時%i分');

実行結果:

2025年02月01日 15時30分

■ 12時間+AM/PM

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %h:%i:%s %p');

実行結果:

2025-02-01 03:30:45 PM

3.3 MySQL 時刻のみフォーマット:TIME_FORMAT()

TIME 型データ専用のフォーマット関数です。

SELECT TIME_FORMAT(CURTIME(), '%H:%i');

実行結果:

15:30

注意点

  • TIME_FORMAT() は TIME型専用
  • DATETIME型には通常 DATE_FORMAT() を使用

3.4 文字列 → 日時変換:STR_TO_DATE()

文字列データを日時型に変換する場合:

SELECT STR_TO_DATE('2025-02-01 15:30:45', '%Y-%m-%d %H:%i:%s');

実行結果:

2025-02-01 15:30:45

よくある失敗

  • フォーマット記号の不一致で NULL が返る
  • %m%c(ゼロ埋め有無)の違いを混同

3.5 実務で注意すべき重要ポイント

❌ フォーマットしてから比較しない

NG例:

WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-02-01';

これはインデックスが効かなくなる(検索高速化が無効)ため非推奨です。

推奨:

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

❌ 表示用フォーマットをDB側でやりすぎない

  • Webアプリでは表示整形はアプリ側で行う方が柔軟
  • DB側は「保存と計算」に集中させる設計が一般的

3.6 ミリ秒を含むフォーマット

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

%f はマイクロ秒(6桁)です。

注意

  • カラムが DATETIME(3) などでないと切り捨てられる
  • MySQL 5.6以降で有効

3.7 まとめ(フォーマット用途別)

目的関数
表示変更DATE_FORMAT
時刻のみ整形TIME_FORMAT
文字列→日時変換STR_TO_DATE
ミリ秒表示%f

4. MySQL 日時 加算・減算(DATE_ADD / DATE_SUB)

現在時刻を取得できても、「◯日後」「◯時間前」などの日時計算ができなければ実務では不十分です。
ここでは DATE_ADD()DATE_SUB() を中心に、MySQLで現在時刻を使った加算・減算の方法を解説します。

4.1 MySQL 日時 加算:DATE_ADD()

基本構文:

SELECT DATE_ADD(基準日時, INTERVAL 数値 単位);

例:現在時刻から7日後

SELECT DATE_ADD(NOW(), INTERVAL 7 DAY);

例:2時間後

SELECT DATE_ADD(NOW(), INTERVAL 2 HOUR);

よく使う単位

単位意味
SECOND
MINUTE
HOUR時間
DAY
MONTH
YEAR

4.2 MySQL 日時 減算:DATE_SUB()

基本構文:

SELECT DATE_SUB(基準日時, INTERVAL 数値 単位);

例:30日前

SELECT DATE_SUB(NOW(), INTERVAL 30 DAY);

例:1時間前

SELECT DATE_SUB(NOW(), INTERVAL 1 HOUR);

用途例

  • 有効期限の判定
  • 古いログの削除
  • 直近データ抽出

4.3 実務でよく使うパターン

■ 直近24時間のデータ取得

SELECT *
FROM logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 DAY);

■ 7日後の期限設定

INSERT INTO tasks (deadline)
VALUES (DATE_ADD(NOW(), INTERVAL 7 DAY));

4.4 よくある失敗と注意点

❌ カラム側に関数をかける

NG例:

WHERE DATE(created_at) = CURDATE();

これはインデックス(検索高速化)が無効になります。

推奨:

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

❌ タイムゾーン未考慮

  • NOW() はサーバータイムゾーン基準
  • UTC保存設計なら UTC_TIMESTAMP() を基準にする

例:

SELECT DATE_ADD(UTC_TIMESTAMP(), INTERVAL 1 DAY);

❌ 月加算の落とし穴

SELECT DATE_ADD('2025-01-31', INTERVAL 1 MONTH);

→ 月末処理の影響で日付が調整される場合があります。
(結果は環境により 2025-02-28 などになる)

月単位計算は仕様を理解した上で使用してください。

4.5 ミリ秒付き加算

SELECT DATE_ADD(NOW(3), INTERVAL 500 MILLISECOND);

※ MySQLでは直接 MILLISECOND 単位は指定不可。
マイクロ秒で指定します:

SELECT DATE_ADD(NOW(3), INTERVAL 500000 MICROSECOND);

4.6 ベストプラクティス

  • 基準は NOW() または UTC_TIMESTAMP() に統一
  • WHERE句ではカラムに関数をかけない
  • 月単位加算は仕様を確認
  • 精度が必要なら DATETIME(3) 以上を使用

5. MySQL 日時差 分(TIMESTAMPDIFF / DATEDIFF)

「MySQL 日時差」「MySQL 日付 差 分」と検索する場合、目的はほぼ次のいずれかです。

  • 2つの日時の差を秒・分・時間で知りたい
  • 日数の差を求めたい
  • 経過時間を数値で扱いたい

MySQLでは主に TIMESTAMPDIFF()DATEDIFF() を使用します。

5.1 MySQL 日時差(秒・分・時間):TIMESTAMPDIFF()

基本構文:

SELECT TIMESTAMPDIFF(単位, 開始日時, 終了日時);

例:現在時刻までの経過時間(分)

SELECT TIMESTAMPDIFF(MINUTE, '2025-02-01 10:00:00', NOW());

使用可能な主な単位

単位説明
SECOND秒差
MINUTE分差
HOUR時間差
DAY日差
MONTH月差
YEAR年差

例:秒差

SELECT TIMESTAMPDIFF(SECOND,
       '2025-02-01 10:00:00',
       NOW());

5.2 MySQL 日数差:DATEDIFF()

日付の差のみ求める場合は DATEDIFF() が簡潔です。

SELECT DATEDIFF('2025-02-10', '2025-02-01');

結果:

9

特徴

  • 時刻部分は無視される
  • 戻り値は日数のみ

5.3 TIMESTAMPDIFF と DATEDIFF の違い

関数時刻考慮単位指定用途
TIMESTAMPDIFFあり必須秒〜年まで柔軟
DATEDIFFなし不可日数のみ

5.4 よくある失敗(重要)

❌ 丸め処理に注意

SELECT TIMESTAMPDIFF(DAY,
       '2025-02-01 23:59:59',
       '2025-02-02 00:00:01');

結果:

0

理由:

  • 単位ごとに切り捨て計算される

より正確に秒単位で取得:

SELECT TIMESTAMPDIFF(SECOND,
       '2025-02-01 23:59:59',
       '2025-02-02 00:00:01');

❌ 負の値になるケース

開始日時が未来の場合:

SELECT TIMESTAMPDIFF(DAY, NOW(), '2025-01-01');

負の値になります。

必要に応じて ABS() を使用:

SELECT ABS(TIMESTAMPDIFF(DAY, NOW(), '2025-01-01'));

5.5 秒 ↔ 時間 変換

■ TIME_TO_SEC()

SELECT TIME_TO_SEC('01:30:00');

結果:

5400

■ SEC_TO_TIME()

SELECT SEC_TO_TIME(5400);

結果:

01:30:00

5.6 実務でよく使うパターン

■ 有効期限チェック

SELECT *
FROM sessions
WHERE TIMESTAMPDIFF(MINUTE, last_access, NOW()) > 30;

■ 経過日数の計算

SELECT TIMESTAMPDIFF(DAY, created_at, NOW()) AS days_passed
FROM orders;

5.7 ベストプラクティス

  • 秒単位で取得し、アプリ側で整形する方が安全
  • 切り捨て挙動を理解する
  • DATEDIFFは日数専用と覚える
  • UTC設計なら UTC_TIMESTAMP() を使用

6. MySQL 期間検索(現在時刻を使ったWHERE条件)

「MySQL 今日のデータを取得」「MySQL 今月のデータ 抽出」などの検索意図では、正しいWHERE条件の書き方が最重要です。
特に、インデックス(検索高速化の仕組み)を無効にしない書き方を理解する必要があります。

6.1 MySQL 今日のデータを取得(インデックスを効かせる)

❌ よくあるNG例(インデックスが効かない)

SELECT *
FROM orders
WHERE DATE(created_at) = CURDATE();

理由:

  • created_at に関数をかけると、インデックスが使われなくなる
  • データ量が多いと著しく遅くなる

✅ 推奨(範囲検索)

SELECT *
FROM orders
WHERE created_at >= CURDATE()
  AND created_at < DATE_ADD(CURDATE(), INTERVAL 1 DAY);

メリット:

  • インデックスが有効
  • 高速
  • 実務で最も使われる書き方

6.2 MySQL 今月のデータを取得(安全な書き方)

■ 今月の開始日を取得

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

しかし、WHEREで直接フォーマット関数を使うのは避けます。

✅ 推奨形

SELECT *
FROM orders
WHERE created_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
  AND created_at < DATE_ADD(
        DATE_FORMAT(CURDATE(), '%Y-%m-01'),
        INTERVAL 1 MONTH
      );

※ 実務ではアプリ側で月初日を計算する方が安全な場合もあります。

6.3 直近◯時間・◯日検索

■ 直近24時間

SELECT *
FROM logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 DAY);

■ 直近7日間

SELECT *
FROM logs
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY);

6.4 UTC設計の場合の注意

UTCで保存している場合:

SELECT *
FROM logs
WHERE created_at >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 1 DAY);

ローカル時間と混在させないことが重要です。

6.5 BETWEENの注意点

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

問題:

  • 上限日が 2025-02-02 00:00:00 までしか含まれない
  • 1日分を正しく取得できない

推奨:

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

6.6 ミリ秒対応カラムの場合

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

小数秒精度に合わせて比較する必要があります。

6.7 パフォーマンス最適化のポイント

  • WHERE句でカラムに関数をかけない
  • 範囲検索(>= と <)を使う
  • タイムゾーンを統一する
  • インデックスを created_at に貼る

例:

CREATE INDEX idx_created_at ON orders(created_at);

6.8 よくある失敗

  • DATE()を使って検索が遅くなる
  • UTCとJSTを混在
  • BETWEENで上限を含め忘れる
  • 文字列型で日時を保存している(非推奨)

7. MySQL タイムゾーン 確認・変更(time_zone / system_time_zone)

「MySQL 現在時刻 ずれる」「NOW() が9時間違う」といった問題の原因の多くは、タイムゾーン設定の理解不足です。ここでは確認方法・変更方法・変換関数の正しい使い方を整理します。

7.1 MySQL タイムゾーン 確認:SHOW VARIABLES

現在のタイムゾーンを確認します。

SHOW VARIABLES LIKE '%time_zone%';

代表的な項目:

  • system_time_zone:OSのタイムゾーン
  • time_zone:MySQLセッションのタイムゾーン

system_time_zone : UTC
time_zone        : SYSTEM

time_zone = SYSTEM の場合、OS設定に依存します。

つまずきポイント

  • サーバーはUTC、開発環境はJSTというケースが多い
  • クラウド環境ではUTCがデフォルトのことが多い

7.2 MySQL タイムゾーン 変更(セッション単位)

現在の接続だけ変更する場合:

SET time_zone = 'Asia/Tokyo';

または:

SET time_zone = '+09:00';

影響範囲

  • 現在の接続のみ有効
  • 再接続すると元に戻る

確認

SELECT NOW();

7.3 MySQL タイムゾーン 変更(サーバー全体)

my.cnf または my.ini に設定:

[mysqld]
default-time-zone = '+09:00'

設定後は再起動が必要:

sudo systemctl restart mysql

注意

  • 本番環境では変更前に影響範囲を確認
  • レプリケーション構成では慎重に行う

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

異なるタイムゾーンへ変換する関数です。

SELECT CONVERT_TZ(NOW(), 'Asia/Tokyo', 'UTC');

例:UTC → ニューヨーク

SELECT CONVERT_TZ(UTC_TIMESTAMP(), 'UTC', 'America/New_York');

7.5 CONVERT_TZ が NULL になる原因

よくあるエラー:

NULL

原因:

  • タイムゾーンテーブルがロードされていない

確認方法:

SELECT CONVERT_TZ(NOW(),'UTC','Asia/Tokyo');

NULLなら未設定の可能性が高い。

解決方法(Linux例)

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

重要

  • マネージドDBでは操作不可の場合あり
  • その場合はオフセット指定(’+09:00’)で対応

7.6 TIMESTAMP と DATETIME のタイムゾーン影響

タイムゾーン影響
TIMESTAMP保存時にUTC変換される
DATETIME変換されない(そのまま保存)

例:

CREATE TABLE test (
    ts_col TIMESTAMP,
    dt_col DATETIME
);
  • TIMESTAMP → UTC基準保存
  • DATETIME → 入力値そのまま保存

7.7 実務ベストプラクティス

  • グローバル対応 → UTC保存(TIMESTAMP推奨)
  • ローカル専用 → DATETIMEでも可
  • アプリ表示時にタイムゾーン変換
  • DB内でTZ変換しすぎない

7.8 よくある失敗

  • UTC保存しているのにJST前提で比較
  • CONVERT_TZがNULLになる
  • セッションTZ変更を忘れる
  • 開発と本番でTZが異なる

8. MySQL DATETIME と TIMESTAMP の違い(タイムゾーンの影響)

「MySQL DATETIME TIMESTAMP 違い」は非常に検索需要の高いテーマです。
現在時刻を扱う設計で型の選択を誤ると、時刻ズレ・集計ミス・表示不整合の原因になります。

8.1 DATETIME:タイムゾーン変換されない(固定値)

DATETIME入力した値がそのまま保存される型です。

CREATE TABLE example (
    event_time DATETIME
);

例:

INSERT INTO example VALUES ('2025-02-01 15:30:00');

保存される値:

2025-02-01 15:30:00

特徴

  • タイムゾーン変換なし
  • 表示も保存値そのまま
  • ローカル時間管理に向いている

8.2 TIMESTAMP:UTC変換される(環境依存)

TIMESTAMP は保存時にUTCへ変換されます。

CREATE TABLE example (
    event_time TIMESTAMP
);

JST環境(+09:00)で:

INSERT INTO example VALUES ('2025-02-01 15:30:00');

内部保存:

  • UTCに変換 → 2025-02-01 06:30:00

取得時:

  • セッションTZに応じて再変換

重要

  • 保存はUTC基準
  • 表示は接続タイムゾーン依存

8.3 動作比較まとめ

項目DATETIMETIMESTAMP
保存時変換なしUTCへ変換
表示時変換なしセッションTZで変換
推奨用途ローカル時間固定グローバルサービス
自動更新可能可能

8.4 実務での選択基準

■ グローバル対応サービス

  • TIMESTAMP + UTC保存
  • 表示時にユーザーTZへ変換

理由:

  • 時差管理が容易
  • サーバー移行時も安全

■ ローカル業務システム(国内のみ)

  • DATETIMEでも問題なし
  • タイムゾーン変換不要

8.5 よくある失敗

❌ DATETIMEでUTC保存しているつもり

→ アプリがJST前提ならズレる

❌ TIMESTAMPを理解せずに使用

→ 「9時間ズレている」と誤解

❌ UTCとローカル時間混在

→ 比較ロジックが破綻

8.6 ミリ秒精度の扱い

両方とも小数秒対応可能(MySQL 5.6以降)

DATETIME(3)
TIMESTAMP(3)

注意:

  • 精度を合わせないと切り捨て発生
  • アプリ側もミリ秒対応必須

8.7 ベストプラクティス(推奨設計)

  • 原則UTC保存
  • DBはTIMESTAMP(3)
  • アプリ層でタイムゾーン変換
  • 期間検索はUTC基準で実施

9. MySQL 現在時刻 実務例(ログ・更新日時・スケジュール)

ここでは、MySQL 現在時刻の実務での具体的な使い方を解説します。
単なる取得方法ではなく、「どう設計すべきか」「どこで失敗しやすいか」に焦点を当てます。

9.1 created_at / updated_at を自動記録する

最も一般的な用途は、レコードの作成日時・更新日時の自動管理です。

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

動作

  • INSERT時 → created_at / updated_at 自動設定
  • UPDATE時 → updated_at 自動更新

つまずきやすい点

  • DATETIME型にするとタイムゾーン変換されない
  • 小数秒精度を揃えないと切り捨てられる
  • アプリ側で上書きしてしまう

9.2 セッション有効期限の管理

ログインセッションの有効期限チェック例:

SELECT *
FROM sessions
WHERE last_access >= DATE_SUB(NOW(), INTERVAL 30 MINUTE);

ポイント

  • カラムに関数をかけない
  • UTC保存設計なら UTC_TIMESTAMP() を使用

9.3 スケジュール管理(未来日時の保存)

例:7日後の締切を登録

INSERT INTO tasks (deadline)
VALUES (DATE_ADD(NOW(), INTERVAL 7 DAY));

注意

  • 月加算は日付調整が発生する場合あり
  • ユーザーTZとサーバーTZの整合性確認が必要

9.4 古いデータの自動削除(データ保持期間)

30日以上前のログ削除:

DELETE FROM logs
WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);

実務ポイント

  • created_at にインデックス必須
  • 大量削除はバッチ分割推奨
  • 本番環境ではバックアップ確認

9.5 アクセスログの記録

CREATE TABLE access_logs (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    access_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

ログ挿入:

INSERT INTO access_logs (user_id) VALUES (123);

設計のコツ

  • 高頻度ログはパーティション検討
  • UTC保存が安全
  • 不要になったログの自動削除設計必須

9.6 実務でよくある失敗

❌ 文字列型で日時保存
→ 比較・並び替え・計算で不具合発生

❌ アプリとDBでタイムゾーン不一致
→ 表示ズレ

❌ インデックスなしで期間検索
→ パフォーマンス劣化

❌ ミリ秒未対応設計
→ 重複データ判定ミス

9.7 設計ベストプラクティス

  • UTC保存(TIMESTAMP(3))
  • created_at / updated_at 自動管理
  • 期間検索は範囲指定
  • ログ系は保持期間ポリシーを明確化

10. MySQL 現在時刻 ずれる・取得できない(よくあるエラー)

「MySQL 現在時刻 ずれる」「NOW() 時刻 おかしい」といったトラブルは非常に多いです。
ここでは原因と具体的な解決手順を整理します。

10.1 NOW() が9時間ずれる(UTC問題)

症状

  • NOW() が日本時間より9時間遅い
  • 本番環境だけ時刻が違う

原因

  • サーバーがUTCで動作している
  • time_zone = SYSTEM でOSがUTC

確認方法

SHOW VARIABLES LIKE '%time_zone%';

解決策(セッション単位)

SET time_zone = 'Asia/Tokyo';

恒久対応(推奨)

  • UTC保存を前提設計に変更
  • 表示時にアプリ側で変換

10.2 CONVERT_TZ() が NULL になる

症状

SELECT CONVERT_TZ(NOW(),'UTC','Asia/Tokyo');

→ NULL

原因

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

解決(Linux例)

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

マネージドDBの場合

  • タイムゾーン名ではなくオフセット使用
SELECT CONVERT_TZ(NOW(), '+00:00', '+09:00');

10.3 TIMESTAMPDIFF の結果が想定外

原因

  • 単位ごとに切り捨て計算
  • 時刻境界で0になる

例:

SELECT TIMESTAMPDIFF(DAY,
       '2025-02-01 23:59:59',
       '2025-02-02 00:00:01');

→ 0

解決

  • 秒単位で取得して計算
SELECT TIMESTAMPDIFF(SECOND,
       '2025-02-01 23:59:59',
       '2025-02-02 00:00:01');

10.4 DATETIME と TIMESTAMP の誤解

症状

  • 保存後に時刻が変わって見える
  • サーバー移行で時間がズレた

原因

  • TIMESTAMPはUTC変換される
  • セッションTZ依存表示

解決策

  • UTC設計ならTIMESTAMP
  • 固定値管理ならDATETIME
  • 設計を統一

10.5 ミリ秒が保存されない

原因

  • カラムが DATETIME(3) ではない
  • CURRENT_TIMESTAMP(3) を指定していない

正しい例

DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3)

10.6 期間検索が遅い

原因

  • DATE()などの関数をカラムに使用
  • インデックス未設定

NG例

WHERE DATE(created_at) = CURDATE();

推奨

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

インデックス作成:

CREATE INDEX idx_created_at ON logs(created_at);

10.7 よくある設計ミスまとめ

  • UTCとローカル混在
  • 文字列型保存
  • ミリ秒未考慮
  • 本番と開発でTZ違い
  • インデックス未設定

11. MySQL 現在時刻 FAQ

ここでは、実務で頻出する疑問を短く正確に整理します。

11.1 NOW() と CURRENT_TIMESTAMP はどちらが速い?

結論:実務上の速度差は無視できるレベルです。

  • 両者はほぼ同義(内部的に同じ値を返す)
  • パフォーマンス差よりも「用途で選ぶ」ことが重要

推奨

  • SELECT用途 → NOW()
  • デフォルト値設定 → CURRENT_TIMESTAMP

11.2 クエリ内で同じ時刻を使いたい場合は?

NOW() は1ステートメント内で固定されます。

SELECT NOW(), SLEEP(3), NOW();

→ 同じ値が返る

一方、SYSDATE() は呼び出し時刻になります。

SELECT SYSDATE(), SLEEP(3), SYSDATE();

→ 値が変わる

整合性重視なら NOW() を使用

11.3 MySQL で UTC保存するのが正解?

グローバルサービスならUTC保存が基本です。

理由:

  • サーバー移行時も安全
  • 多地域ユーザー対応が容易
  • 表示時にTZ変換可能

設計例:

TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3)

11.4 DATETIME と TIMESTAMP のどちらを選ぶ?

ケース推奨型
国際サービスTIMESTAMP
ローカル固定時間DATETIME
TZ変換不要DATETIME
ログ管理TIMESTAMP

迷ったらUTC保存+TIMESTAMPが安全

11.5 ミリ秒対応の正しい設定は?

DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3)

または

TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3)

注意:

  • 型とDEFAULTの精度を一致させる
  • MySQL 5.6以上必須

11.6 期間検索で BETWEEN を使ってよい?

基本は非推奨です。

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

→ 上限の時刻を含まない

推奨:

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

11.7 なぜ NOW() が本番だけズレる?

原因のほとんどは:

  • 本番がUTC
  • 開発がJST
  • セッションTZ未設定

確認:

SHOW VARIABLES LIKE '%time_zone%';

12. MySQL 現在時刻 まとめ(目的別の最短SQL再掲)

本記事の内容を、検索意図ごとの最短SQLとして整理します。実務で迷った場合は、まずここを確認してください。

12.1 現在時刻を取得したい

■ 現在日時(最も基本)

SELECT NOW();

または

SELECT CURRENT_TIMESTAMP;

■ UTCで取得

SELECT UTC_TIMESTAMP();

■ 日付のみ

SELECT CURDATE();

■ 時刻のみ

SELECT CURTIME();

■ ミリ秒付き

SELECT NOW(3);

12.2 デフォルト値として自動記録したい

created_at TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3),
updated_at TIMESTAMP(3)
    DEFAULT CURRENT_TIMESTAMP(3)
    ON UPDATE CURRENT_TIMESTAMP(3)

注意

  • 型と精度を一致させる
  • UTC保存設計が安全

12.3 日時を加算・減算したい

■ 7日後

SELECT DATE_ADD(NOW(), INTERVAL 7 DAY);

■ 30日前

SELECT DATE_SUB(NOW(), INTERVAL 30 DAY);

■ 直近24時間検索

WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 DAY);

12.4 2つの日時の差を求めたい

■ 秒差

SELECT TIMESTAMPDIFF(SECOND, start_time, end_time);

■ 日数差

SELECT DATEDIFF(end_date, start_date);

12.5 今日・今月のデータを取得したい

■ 今日

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

■ 今月

WHERE created_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
  AND created_at < DATE_ADD(
        DATE_FORMAT(CURDATE(), '%Y-%m-01'),
        INTERVAL 1 MONTH
      );

12.6 タイムゾーンを確認・変更したい

■ 確認

SHOW VARIABLES LIKE '%time_zone%';

■ セッション変更

SET time_zone = 'Asia/Tokyo';

■ タイムゾーン変換

SELECT CONVERT_TZ(NOW(), 'UTC', 'Asia/Tokyo');

12.7 DATETIME と TIMESTAMP の使い分け

  • グローバル対応 → TIMESTAMP(UTC保存)
  • ローカル固定 → DATETIME
  • ミリ秒必要 → (3)以上指定

12.8 最重要チェックリスト

  • UTCとローカルを混在させない
  • WHEREでカラムに関数をかけない
  • インデックスを貼る
  • 精度(ミリ秒)を揃える
  • 本番環境のタイムゾーンを確認

MySQLの現在時刻は、取得・計算・検索・設計の4つを正しく理解することが安定運用の鍵です。
ここまで理解できれば、実務での時刻処理で大きく失敗することはありません。