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 位元系統或改用 DATETIME
。DATETIME
可支援西元 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
。
最後,應根據系統需求選擇 TIMESTAMP
或 DATETIME
,以確保資料一致性與維護性。
8. 常見問題(FAQ)
以下整理一些 MySQL TIMESTAMP
的常見疑問與解答:
TIMESTAMP
與 DATETIME
該如何選擇?
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');
因此,兩者並不衝突。