本文 AI 產出,尚未審核
MySQL 日期時間型別:DATE、DATETIME 與 TIMESTAMP 完全指南
簡介
在資料庫設計裡,時間資訊往往是最關鍵的欄位,無論是訂單建立時間、使用者最後登入時間,還是報表統計的區間,都離不開正確的日期與時間儲存。MySQL 提供了多種日期時間型別,其中最常用的三個是 DATE、DATETIME 與 TIMESTAMP。它們看似相似,實際上在儲存範圍、時區處理、預設值與效能上都有顯著差異。了解這些差異,才能避免資料錯誤、查詢效能下降,甚至產生跨時區的混亂。
本篇文章針對 初學者到中級開發者,以淺顯易懂的語言說明三種型別的特性、使用時機與常見陷阱,並提供實務範例,協助你在 MySQL 中正確、有效率地處理日期時間資料。
核心概念
1. DATE
| 屬性 | 說明 |
|---|---|
| 儲存格式 | YYYY‑MM‑DD(僅包含日期) |
| 儲存空間 | 3 bytes |
| 支援範圍 | 1000‑01‑01 ~ 9999‑12‑31 |
| 時區 | 不受時區影響,純粹的日曆日期 |
使用時機
- 只需要記錄「是哪一天」的情境,例如生日、節假日、會計期間等。
- 不需要考慮時區或時間的精確度。
範例
-- 建立僅儲存日期的欄位
CREATE TABLE employee (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
birth_date DATE NOT NULL -- 生日
);
-- 插入資料,MySQL 會自動檢查合法性
INSERT INTO employee (name, birth_date)
VALUES ('王小明', '1990-05-12');
-- 查詢 1990 年出生的員工
SELECT * FROM employee
WHERE birth_date BETWEEN '1990-01-01' AND '1990-12-31';
2. DATETIME
| 屬性 | 說明 |
|---|---|
| 儲存格式 | YYYY‑MM‑DD HH:MM:SS(不含時區) |
| 儲存空間 | 5 bytes(DATETIME(0))或 6~8 bytes(支援小數秒) |
| 支援範圍 | 1000‑01‑01 00:00:00 ~ 9999‑12‑31 23:59:59 |
| 時區 | 與伺服器時區無關,儲存時不會自動轉換 |
使用時機
- 必須同時保存「日期」與「時間」且不想受到時區影響的情況,例如歷史事件、預約時間(固定於特定時區)等。
- 需要更高精度(可使用
DATETIME(3)、DATETIME(6))時。
範例
-- 建立 DATETIME 欄位,預設值為目前時間
CREATE TABLE meeting (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
start_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
end_time DATETIME NOT NULL
);
-- 插入會議資料,手動指定結束時間
INSERT INTO meeting (title, end_time)
VALUES ('產品發表會', '2025-12-01 15:30:00');
-- 取得今天之後的所有會議
SELECT *
FROM meeting
WHERE start_time >= CURDATE();
3. TIMESTAMP
| 屬性 | 說明 |
|---|---|
| 儲存格式 | Unix epoch(自 1970‑01‑01 00:00:01 UTC 起的秒數) |
| 儲存空間 | 4 bytes |
| 支援範圍 | 1970‑01‑01 00:00:01 UTC ~ 2038‑01‑19 03:14:07 UTC |
| 時區 | 受伺服器與連線時區影響,寫入時會自動轉換為 UTC,讀取時再依當前時區轉回本地時間 |
使用時機
- 需要自動追蹤建立或更新時間(
DEFAULT CURRENT_TIMESTAMP、ON UPDATE CURRENT_TIMESTAMP)時最常使用。 - 系統間同步資料、日誌紀錄、或需要以 UTC 為基準的分散式應用。
範例
-- 建立自動紀錄建立與更新時間的表
CREATE TABLE audit_log (
id INT PRIMARY KEY AUTO_INCREMENT,
action VARCHAR(200) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 新增一筆紀錄
INSERT INTO audit_log (action) VALUES ('使用者登入');
-- 模擬更新(updated_at 會自動更新)
UPDATE audit_log SET action = '使用者登出' WHERE id = 1;
-- 查詢並顯示 UTC 與本地時間差異
SELECT id,
action,
created_at,
CONVERT_TZ(created_at, @@session.time_zone, '+00:00') AS created_utc
FROM audit_log;
4. 小結:何時選哪個?
| 需求 | 建議型別 |
|---|---|
| 只需要日期(不含時間) | DATE |
| 需要日期+時間且 不受時區 影響 | DATETIME |
| 需要自動追蹤、跨時區同步或以 UTC 為基準 | TIMESTAMP |
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
| 時區混亂 | TIMESTAMP 會自動依伺服器時區轉換,若開發、測試、正式環境時區不同,會造成時間錯位。 |
統一時區:在 my.cnf 設定 default_time_zone = '+00:00',或在連線時使用 SET time_zone = '+08:00';。 |
| 超出範圍 | TIMESTAMP 只能到 2038 年,若儲存未來遠期的日期(例如合約到 2050 年),會溢位。 |
使用 DATETIME 取代 TIMESTAMP。 |
| 預設值不一致 | DATETIME 在 MySQL 5.6 以前不支援 DEFAULT CURRENT_TIMESTAMP,會導致欄位預設為 NULL。 |
確認 MySQL 版本,或改用 TIMESTAMP 作為自動時間戳記欄位。 |
| 毫秒/微秒需求 | DATE、DATETIME、TIMESTAMP 預設不支援小數秒。 |
使用 DATETIME(3)、DATETIME(6) 或 TIMESTAMP(6)(MySQL 5.6+)來儲存毫秒/微秒。 |
| 字串與日期比較 | 直接比較 '2025-01-01' 與 DATETIME 可能觸發隱式轉型,降低效能。 |
使用適當的類型,或在比較前使用 CAST(... AS DATETIME),並確保欄位上有索引。 |
最佳實踐:
- 統一時區:開發、測試、上線皆使用 UTC,前端再根據使用者時區顯示。
- 使用
TIMESTAMP作為 audit 欄位:自動ON UPDATE CURRENT_TIMESTAMP減少程式碼。 - 為日期欄位加索引:查詢範圍(
BETWEEN)時效能大幅提升。 - 避免在
DATETIME上使用DEFAULT CURRENT_TIMESTAMP(除非 MySQL 5.6+),以免兼容性問題。 - 明確命名:如
created_at、updated_at、event_date,讓欄位意圖一目了然。
實際應用場景
1. 電子商務 – 訂單流程
| 欄位 | 型別 | 為何選此型別 |
|---|---|---|
order_date |
DATETIME |
訂單產生的本地時間,需要精確到秒,且不因時區變化而改變(平台固定於台北時間)。 |
payment_timestamp |
TIMESTAMP |
付款系統使用 UTC 記錄,便於跨國金融機構對帳。 |
delivery_deadline |
DATE |
僅需顯示「送達日期」,不必關心時間。 |
2. 內容管理系統(CMS) – 文章發佈
published_at使用TIMESTAMP:允許排程發佈(未來時間),同時系統會自動轉為 UTC,避免因伺服器搬遷造成時間錯亂。last_edited使用DATETIME:編輯者希望看到本地時間的編輯紀錄。archive_date使用DATE:僅標示文章何時歸檔。
3. IoT 平台 – 感測資料
感測器上傳的資料包含毫秒級時間戳記,適合使用 TIMESTAMP(6),儲存 UTC,便於跨時區聚合與分析。
總結
DATE:僅記錄日期、儲存空間最小、與時區無關,適合生日、節假日等純日曆資訊。DATETIME:記錄完整的「日期+時間」且不受時區影響,適合固定時區的業務流程或需要高精度的時間點。TIMESTAMP:以 UTC 儲存、會自動依時區轉換,適合自動追蹤、跨時區同步或需要以 epoch 為基礎的系統。
在設計資料表時,先明確需求(是否需要時區、是否需要自動更新、時間範圍)再挑選最適合的型別,才能避免日後的資料錯誤與效能瓶頸。記得統一時區、加索引、善用 MySQL 提供的預設值與自動更新功能,讓你的 MySQL 應用更穩定、維護更輕鬆。祝你在 MySQL 的日期時間世界裡玩得開心!