你的created_time字段,用DATETIME还是TIMESTAMP?
故事场景:记录一场全球同步直播的发布会
你是一位历史记录员,你的任务是精确记录一场从北京时间上午10点开始的、全球同步直播的科技发布会的召开时刻。你有两种时钟可以参考。
时钟A:DATETIME
— “本地会议室的石英挂钟”
这是一个挂在墙上、走时精准的石英钟。
• 记录方式:
发布会开始时,你抬头看了一眼墙上的石英钟,指针不多不少,正好指向上午10:00。于是,你在你的档案(数据库)里写下:“事件发生于:10:00”。• 特点:
• 所见即所得,与时区无关 (Timezone-Independent): 这个时钟只管显示它本地的时间。它本身不包含“我是北京时间”这个信息。
• 解读依赖上下文: 几天后,你远在伦敦的同事调阅了这份档案,他看到的是“事件发生于:10:00”。如果他不知道这是你当初在北京记录的,他可能会误以为是伦敦时间的上午10点。这份记录是字面上的、固定的,不具备时区自适应能力。
• 何时使用它?
当你需要记录一个与时区无关的、绝对的日期和时间时。比如用户的生日(1990-05-20
,我们不关心他是几点、在哪个时区出生的),或者某个在特定时区举行的固定活动时间(比如“本店每天北京时间9点开门”,这个“9点”不会因为你在纽约看就变成别的数字)。
时钟B:TIMESTAMP
— “连接世界标准时间的智能手表”
这是一块能自动连接到世界标准时间(UTC)并根据你所在位置自动调整显示时间的智能手表。
• 记录方式:
发布会开始时,你在北京,你的智能手表显示的是上午10:00。你按下了记录按钮。手表内部并没有简单地存下“10:00”,而是立刻进行了一次换算:“北京时间(UTC+8)的上午10点,就是世界标准时间(UTC)的凌晨2点”。它在后台真正存储的是这个全球唯一的时刻——UTC 2:00。• 特点:
• 自动转换,与时区相关 (Timezone-Aware): 它的核心是存储一个绝对的、不随地点改变的时间点(UTC时间)。
• 显示本地化: 你的伦敦同事(UTC+1夏令时)调阅这份记录时,他的智能终端会从档案中读取“UTC 2:00”,并自动转换成他当地的时间,显示为“事件发生于:凌晨3:00”。同样,纽约的同事(UTC-4)看到的则是“事件发生于:晚上10:00(前一天)”。虽然大家看到的显示值不同,但都指向了同一个宇宙中的精确瞬间。
• 何时使用它?
当记录事件发生的那个精确瞬间至关重要时。比如,用户注册时间、发帖时间、订单支付时间、记录的最后修改时间(created_at
,updated_at
)。这些场景下,我们关心的是事件发生的绝对时间点,并希望它能在全球各地被正确地理解。
故事总结:
特性 | DATETIME (本地挂钟) | TIMESTAMP (世界标准手表) |
时区处理 | 与时区无关 | 与时区相关 (存入时转为UTC,取出时转为当前时区) |
存储范围 | 大 ( | 小 ( |
存储空间 | 较大 (5-8字节) | 较小 (4字节) |
核心比喻 | 一张本地时间的照片 | 一个全球同步的时间戳 |
一句话选择 | 我就要存这个“所见即所得”的时间! | 我要记录下“此时此刻”这个瞬间! |
一个重要的历史注记:
在旧版的MySQL中,TIMESTAMP
有一个“特殊优待”——默认情况下,它是第一列时会自动记录创建和更新时间。但在新版MySQL(5.6.5+)中,DATETIME
也获得了同样的能力 (DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)。所以,现在选择它们,主要就是基于“时区”这个核心区别。
技术解析与SQL实验
这个SQL实验将直观地展示 TIMESTAMP
和 DATETIME
在时区变化时的不同表现。
-- 创建一个用于演示的表
CREATE TABLE time_zone_demo (event_description VARCHAR(50),dt_event_time DATETIME, -- 使用 DATETIME 类型ts_event_time TIMESTAMP -- 使用 TIMESTAMP 类型
);-- 假设我们的数据库服务器、客户端都位于“北京时区” (UTC+8)
-- 我们在 “2025-07-20 10:00:00” 这个时刻插入一条记录
INSERT INTO time_zone_demo (event_description, dt_event_time, ts_event_time)
VALUES ('Global Conference Start', '2025-07-20 10:00:00', '2025-07-20 10:00:00');-- 查看当前时区下的数据
SELECT * FROM time_zone_demo;
-- 输出结果 (北京时区, +08:00):
-- event_description | dt_event_time | ts_event_time
-- -------------------------|---------------------|---------------------
-- Global Conference Start | 2025-07-20 10:00:00 | 2025-07-20 10:00:00-- 现在,关键的实验来了!
-- 模拟一个位于“伦敦”的同事来查看这条记录。我们把会话时区切换到伦敦时区 (UTC+0)
SET time_zone = '+00:00';-- 再次查看同一条数据
SELECT * FROM time_zone_demo;
-- 输出结果 (伦敦时区, +00:00):
-- event_description | dt_event_time | ts_event_time
-- -------------------------|---------------------|---------------------
-- Global Conference Start | 2025-07-20 10:00:00 | 2025-07-20 02:00:00 <-- 注意!TIMESTAMP 的值变了!-- 再模拟一个位于“东京”的同事来查看
SET time_zone = '+09:00';-- 再次查看同一条数据
SELECT * FROM time_zone_demo;
-- 输出结果 (东京时区, +09:00):
-- event_description | dt_event_time | ts_event_time
-- -------------------------|---------------------|---------------------
-- Global Conference Start | 2025-07-20 10:00:00 | 2025-07-20 11:00:00 <-- TIMESTAMP 的值又变了!
实验结论:
•
DATETIME
像一个“固执”的记录员,存的是什么,取出来的就是什么,与时区无关。•
TIMESTAMP
像一个“聪明”的翻译官,存储时,它会把当前时区的时间转换成世界标准时间(UTC)来保存;取出时,它又会把UTC时间转换成你当前所在时区的时间来显示