DATETIME 和 TIMESTAMP 有什么区别?
在 MySQL 中,DATETIME
和 TIMESTAMP
都是用于存储日期和时间的数据类型,但它们在工作原理、存储范围、时区处理和存储空间上存在关键区别:
特性 | DATETIME | TIMESTAMP |
---|---|---|
时间范围 | 1000-01-01 00:00:00 到 9999-12-31 23:59:59 | 1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC |
时区处理 | 不涉及时区转换(存储和检索的值完全一致) | 自动转换(存入时转UTC,检索时转当前时区) |
存储空间 | 5字节(MySQL 5.6.4+) | 4字节 |
默认值 | 不支持 CURRENT_TIMESTAMP 作为默认值(除非显式定义) | 支持自动初始化/更新为当前时间(CURRENT_TIMESTAMP ) |
NULL处理 | 允许 NULL ,存储为 NULL | 未显式赋值时自动设置为当前时间(非 NULL ) |
用途场景 | 需要大范围时间存储(如历史/未来日期) | 记录数据的创建/修改时间(自动更新) |
时间范围 (Range):
DATETIME
: 支持更广的范围,从'1000-01-01 00:00:00'
到'9999-12-31 23:59:59'
。适合需要存储历史或未来遥远日期的情况。TIMESTAMP
: 范围小得多,从'1970-01-01 00:00:01' UTC
到'2038-01-19 03:14:07' UTC
。这就是著名的 2038年问题。超出范围的值会被存储为0
(0000-00-00 00:00:00
)或边界值。时区处理 (Time Zone Awareness):
DATETIME
: 与时区无关。你存入的是什么值,检索出来的就是什么值。MySQL 服务器或客户端的时区设置对它没有影响。它不存储任何时区信息。适合存储用户指定的具体时间点(如生日、预约时间)。TIMESTAMP
: 与时区相关。在存储时,MySQL 会将你提供的TIMESTAMP
值 从当前会话的时区转换为协调世界时 (UTC) 进行存储。在检索时,MySQL 会将存储的 UTC 值 转换回当前会话的时区 显示给你。这个行为由 MySQL 服务器的time_zone
系统变量或会话时区设置控制。适合记录事件发生的精确时刻(如日志时间、行创建/更新时间)。存储空间 (Storage Space):
DATETIME
: 在 MySQL 5.6.4 及更高版本中,DATETIME
需要 5 字节 的存储空间(之前的版本是 8 字节)。这 5 字节用于存储一个打包的数字(YYYYMMDD HHMMSS
的整数形式)。TIMESTAMP
: 总是需要 4 字节 的存储空间。它存储的是自 '1970-01-01 00:00:00' UTC 以来的秒数(UNIX 时间戳)。这也是其范围受限的根本原因(4 字节有符号整数的最大值限制)。自动初始化和更新 (Automatic Initialization and Updating):
DATETIME
: 在 MySQL 5.6.5 之前,DATETIME
列不能使用CURRENT_TIMESTAMP
作为默认值或自动更新。从 MySQL 5.6.5 开始,DATETIME
列也支持使用DEFAULT CURRENT_TIMESTAMP
和ON UPDATE CURRENT_TIMESTAMP
属性。TIMESTAMP
: 传统上(且最常用)支持自动初始化(DEFAULT CURRENT_TIMESTAMP
)和自动更新(ON UPDATE CURRENT_TIMESTAMP
)。第一个TIMESTAMP
列(如果未显式指定默认值或更新属性)在旧版本 MySQL 中可能会有特殊行为,但现代版本(5.6.5+)推荐显式定义。可以方便地记录行的创建时间或最后修改时间。NULL 值:
DATETIME
: 可以存储NULL
值。TIMESTAMP
: 如果列定义为NOT NULL
,尝试插入NULL
会被设置为当前时间戳。如果列允许NULL
,插入NULL
则存储NULL
。未显式赋值的TIMESTAMP NOT NULL
列通常会自动获得当前时间戳(取决于默认值设置)。
那么我们如何选择呢?
选择
TIMESTAMP
当:你需要记录事件发生的 精确时刻(如操作日志时间、行创建/更新时间)。
你需要 自动设置创建时间或更新时间(利用
DEFAULT CURRENT_TIMESTAMP
/ON UPDATE CURRENT_TIMESTAMP
)。存储的时间都在 1970 到 2038 年之间。
你希望值能 根据客户端或服务器的时区设置自动转换显示。
对存储空间比较敏感(4字节 vs 5字节)。
选择
DATETIME
当:你需要存储 1970 年之前或 2038 年之后的日期时间(如历史档案、未来计划)。
你存储的时间是 用户指定的、与时区无关的具体时间点(如生日、会议时间
'2080-12-25 15:30:00'
)。你希望 存入的值和检索的值绝对一致,不受服务器或客户端时区设置的影响。
不需要或不依赖自动设置当前时间戳的特性(虽然现代 MySQL 也支持了)。
总结:TIMESTAMP
更适合记录事件发生的 时刻(时刻点,自动转换时区),而 DATETIME
更适合记录 日历/时钟上的具体时间(时间点,固定不变)。务必注意 TIMESTAMP
的 2038 年限制。在现代 MySQL 中(5.6.5+),两者在自动初始化/更新功能上的差异已经很小,主要区别在于范围、时区处理和存储空间。