DATETIME 和 TIMESTAMP 有什么区别?
本文对比了DATETIME和TIMESTAMP。核心区别:DATETIME是时区无关的固定时间;TIMESTAMP是时区相关的UTC时间点,会自动转换。
这是一个在数据库设计中非常经典的问题。DATETIME 和 TIMESTAMP 都用于存储日期和时间,但它们在时区处理、存储空间、取值范围和默认行为上有本质的区别。
简单来说:
DATETIME:存储一个固定的、与时区无关的日期和时间。你存入什么,取出来就是什么。TIMESTAMP:存储一个相对于 UTC(世界标准时间)的时间点。它会根据数据库服务器或客户端的时区设置进行转换。
下面我们来详细分解这些区别。
核心区别详解
1. 时区处理(最重要的区别)
DATETIME: 时区无关 (Timezone-naive)- 它存储的是一个字面上的日期和时间,例如
'2023-10-27 10:00:00'。 - 它不包含任何时区信息。无论你的数据库服务器、操作系统或客户端连接设置在哪个时区,你存入
'2023-10-27 10:00:00',取出来的永远是'2023-10-27 10:00:00'。 - 比喻:就像在一张纸上写下“10月27日上午10点”。这个记录本身是固定的,不会因为你看这张纸时身处北京还是纽约而改变。
- 它存储的是一个字面上的日期和时间,例如
TIMESTAMP: 时区相关 (Timezone-aware)- 当你存入一个时间时,它会先从你当前会话(Session)的时区转换为 UTC 时间(Coordinated Universal Time,世界标准时间)进行存储。
- 当你查询这个时间时,它又会从存储的 UTC 时间转换回你当前会话的时区来显示。
- 比喻:就像记录一个全球性的事件瞬间。比如,一个用户在北京时间(UTC+8)
2023-10-27 10:00:00发布了一篇文章,数据库会将它转换成 UTC 时间2023-10-27 02:00:00存储。当一个在东京(UTC+9)的用户查看时,他看到的时间是2023-10-27 11:00:00。虽然显示的具体时间不同,但它们都指向同一个历史瞬间。
2. 取值范围
DATETIME: 范围非常广。- 通常是
'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。 - 适合存储需要久远历史或未来日期的信息,如出生日期、历史事件等。
- 通常是
TIMESTAMP: 范围相对较小。- 它存储的是自 Unix 纪元(
1970-01-01 00:00:00UTC)以来的秒数。 - 在32位系统中,其范围是
'1970-01-01 00:00:01'UTC 到'2038-01-19 03:14:07'UTC。这就是著名的 “2038年问题”(Y2K38 problem)。 - 虽然现在很多系统是64位的,解决了这个问题,但在设计时仍需考虑兼容性。
- 它存储的是自 Unix 纪元(
3. 存储空间
DATETIME: 存储空间通常较大。- 在 MySQL 5.6.4 之前,固定占用 8个字节。
- 在 MySQL 5.6.4 及之后,它被优化为 5个字节 + 小数秒的额外字节。
TIMESTAMP: 存储空间较小。- 固定占用 4个字节 + 小数秒的额外字节。
- 由于它存储的是一个整数(秒数),所以更节省空间。
4. 自动更新特性(以 MySQL 为例)
DATETIME:- 在旧版本的 MySQL 中,
DATETIME字段需要手动设置或更新。 - 从 MySQL 5.6.5 开始,
DATETIME也可以像TIMESTAMP一样设置DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP。
- 在旧版本的 MySQL 中,
TIMESTAMP:- 这是
TIMESTAMP的一个经典特性。默认情况下,如果你不给TIMESTAMP字段赋值,它会自动设置为当前时间。 - 你还可以定义
ON UPDATE CURRENT_TIMESTAMP,这样每当这一行数据被更新时,该字段的值就会自动更新为当前的系统时间。这使得它非常适合用作created_at和updated_at这样的字段。
- 这是
对比总结表
| 特性 | DATETIME | TIMESTAMP |
|---|---|---|
| 时区处理 | 与时区无关,存储字面值 | 与时区相关,存储为 UTC,按会话时区显示 |
| 取值范围 | 宽 (1000 ~ 9999 年) |
窄 (1970 ~ 2038 年,32位系统) |
| 存储空间 | 较大 (5~8 字节) | 较小 (4 字节) |
| 自动更新 | 新版支持,但非传统特性 | 核心特性,常用于 created_at, updated_at |
| NULL 值 | 允许 | 允许(但如果不允许,会自动设为当前时间) |
我应该用哪个?(选择建议)
选择 DATETIME 的场景:
- 存储一个固定的、不应随地域变化的时间。
- 例如:用户的生日、法定节假日、特定活动的开始时间(如“北京时间晚上8点开始”)。这些时间点是明确的,不应该因为服务器换了地方或用户在不同时区查看而改变。
- 需要存储 1970 年以前或 2038 年以后的日期。
- 例如:历史事件记录、长期的合同到期日等。
选择 TIMESTAMP 的场景:
- 构建国际化应用,需要为不同时区的用户正确显示时间。
- 例如:文章发布时间、消息发送时间、订单创建时间。全球用户看到的应该是他们本地时区的对应时间。
- 记录数据的创建或最后修改时间。
- 例如:
created_at和updated_at字段。TIMESTAMP的自动更新特性完美契合这个需求。
- 例如:
- 对存储空间敏感的场景。
TIMESTAMP更节省空间。
总之,记住这个核心原则:如果你的时间是针对一个全球性的“时刻”,用 TIMESTAMP;如果你的时间是针对一个日历上的“标记”,用 DATETIME。