MySQL TIMESTAMP 與 DATETIME 差異完整教學:用法、時區設定與 2038 年問題解析

1. MySQL 的 timestamp 是什麼?

在 MySQL 中,TIMESTAMP 資料型別會將特定時間以 UTC(協定世界時)儲存,並在儲存或查詢時自動考慮時區來處理。這種類型可以處理從 1970 年 1 月 1 日到 2038 年 1 月 19 日的日期與時間。當資料被寫入資料庫時,TIMESTAMP 會使用目前的時區,之後在查詢時會依據系統時區自動轉換。

TIMESTAMP 與 DATETIME 的差異

TIMESTAMP 常與 DATETIME 做比較。DATETIME 會以原始格式儲存日期時間,不受時區影響。而 TIMESTAMP 則在儲存時轉換為 UTC,在查詢時再依系統時區轉換,避免了跨時區造成的時間誤差。

例如,TIMESTAMP 在系統遷移或跨多個時區的資料庫中特別有用。而 DATETIME 可處理從西元 1000 年到 9999 年的時間範圍,因此常用來避免 2038 年問題。

TIMESTAMP 使用範例

以下範例示範如何使用 TIMESTAMP 建立資料表:

CREATE TABLE events (
    id INT AUTO_INCREMENT PRIMARY KEY,
    event_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

在這個範例中,event_time 欄位會在插入時自動存入當前時間,並在每次更新時自動覆蓋為最新時間。

2. timestamp 的基本用法

在 MySQL 中使用 TIMESTAMP 時,必須熟悉基本的插入與查詢方式。以下介紹幾種常見操作。

插入日期與時間

TIMESTAMP 欄位中插入資料時,通常使用字串格式的日期與時間:日期格式為「YYYY-MM-DD」,時間格式為「hh:mm:ss」。

INSERT INTO events (event_time) VALUES ('2023-10-01 12:30:00');

此 SQL 會在 event_time 欄位插入 2023 年 10 月 1 日 12:30 的時間。

插入當前時間

透過 MySQL 的 NOW() 函數,可以快速取得系統時區下的當前時間,並插入 TIMESTAMP 欄位。

INSERT INTO events (event_time) VALUES (NOW());

此語句會自動插入 SQL 執行當下的時間。

使用自動更新功能

TIMESTAMP 欄位設定 ON UPDATE CURRENT_TIMESTAMP,可在每次資料更新時自動記錄更新時間。

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    order_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

此範例中,order_time 在新增時會自動記錄時間,之後每次更新也會同步更新時間。

3. timestamp 與時區處理

TIMESTAMP 最大的特點之一就是會自動考慮時區。資料儲存時會轉為 UTC,查詢時再依系統時區轉換。

如何確認時區設定

MySQL 可針對伺服器或連線設定時區,可用 SHOW VARIABLES 指令檢查。

SHOW VARIABLES LIKE 'time_zone';

此指令會返回當前資料庫的時區設定。若要修改,可使用:

SET time_zone = '+09:00';

TIMESTAMP 與 DATETIME 的時區差異

DATETIME 不考慮時區,直接存入原始日期時間;而 TIMESTAMP 則會轉換成 UTC。因此在跨時區系統中,使用 TIMESTAMP 更合適。

4. 2038 年問題與影響

所謂「2038 年問題」來自於 32 位元系統 TIMESTAMP 的限制。MySQL 的 TIMESTAMP 基於自 1970 年 1 月 1 日 UTC 起的秒數計算,當超過 2038 年 1 月 19 日 03:14:07 UTC 時,數值會溢出。

如何避免 2038 年問題

建議使用 64 位元系統或改用 DATETIMEDATETIME 可支援西元 1000 到 9999 年,2038 年之後也能安全使用。

另外,升級系統至 64 位元環境也能徹底解決此問題。

5. timestamp 型的應用範例

MySQL 的 TIMESTAMP 型別不僅能用來儲存基本的日期與時間,還能透過自動填入與更新當前時間等功能,延伸出多種應用。以下介紹幾個常見的進階用法。

自動插入當前時間

當設定 TIMESTAMP 欄位時,如果將預設值設為 CURRENT_TIMESTAMP,則每次新增資料時都會自動記錄當前時間。例如,建立一個自動記錄訂單時間的資料表:

CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    order_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

自動記錄更新時間

如果加上 ON UPDATE CURRENT_TIMESTAMP,則每次更新紀錄時會自動更新時間,方便管理修改紀錄。

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

使用多個 TIMESTAMP 欄位

MySQL 一個資料表中可以擁有多個 TIMESTAMP 欄位,但只有一個欄位能設為預設 CURRENT_TIMESTAMP。如果需要管理多個時間點,建議搭配 DATETIME 或明確指定值。

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

6. 使用 timestamp 型時的注意事項

在使用 TIMESTAMP 型別時,有一些需要注意的地方,避免發生資料錯誤或不一致。

NULL 約束與預設值

TIMESTAMP 欄位預設會套用 NOT NULL 約束。如果要允許 NULL,必須明確設定 DEFAULT NULL

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    log_time TIMESTAMP DEFAULT NULL
);

雖然也可以指定 DEFAULT 0 來儲存 0000-00-00 00:00:00,但這在嚴格 SQL 模式下可能導致錯誤,因此不建議。

0000-00-00 00:00:00 的問題

部分 MySQL 版本允許 0000-00-00 00:00:00 這樣的無效時間,但實際應用可能造成資料不一致。建議改用 NULL 或合理的預設值。

CREATE TABLE sessions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    start_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    end_time TIMESTAMP NULL
);

系統時區的影響

由於 TIMESTAMP 儲存時會轉換為 UTC,如果伺服器的時區設定變更,查詢時的時間可能不同。因此必須正確管理時區。

SET time_zone = 'Asia/Tokyo';

透過此設定,可確保 UTC 轉換為東京時區時正確顯示。

7. 總結與建議

TIMESTAMP 是 MySQL 中管理日期與時間的強大工具,特別適合需要時區轉換與自動更新的場合。但必須注意 2038 年問題與 NULL 處理方式,才能確保資料正確性。

TIMESTAMP 的使用建議

  • 若需要自動更新時間,建議使用 TIMESTAMP
  • 若系統需考慮多個時區,則 UTC 轉換的 TIMESTAMP 很實用。
  • 若需長期擴充性或處理 2038 年以後的日期,建議改用 DATETIME

最後,應根據系統需求選擇 TIMESTAMPDATETIME,以確保資料一致性與維護性。

8. 常見問題(FAQ)

以下整理一些 MySQL TIMESTAMP 的常見疑問與解答:

TIMESTAMPDATETIME 該如何選擇?

TIMESTAMP 適合需要自動時區轉換與記錄建立、更新時間的應用;DATETIME 則適合需要固定、不受時區影響的時間紀錄。

TIMESTAMP 在 2038 年之後不能使用嗎?

是的,這是 32 位元系統的限制。2038 年以後會溢出。建議使用 64 位元系統或 DATETIME 來避免此問題。

如何允許 TIMESTAMP 欄位存放 NULL?

必須明確指定 DEFAULT NULL

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    log_time TIMESTAMP DEFAULT NULL
);

若修改時區設定,會影響既有 TIMESTAMP 資料嗎?

會影響顯示結果。資料仍以 UTC 儲存,但查詢時會依新的時區轉換。因此建議系統統一時區設定。

使用 CURRENT_TIMESTAMP 是否就無法插入特定時間?

不是。CURRENT_TIMESTAMP 僅在未指定值時自動填入當前時間。若要插入特定時間,仍可手動指定:

INSERT INTO events (event_time) VALUES ('2023-10-01 12:30:00');

因此,兩者並不衝突。