DATETIME 和 TIMESTAMP 有什么区别?

在 MySQL 中,DATETIMETIMESTAMP 都用于存储日期时间,但它们在 存储方式、范围、时区处理、存储空间 等核心方面有显著区别。以下是详细对比:


核心区别总结

特性DATETIMETIMESTAMP
时间范围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 字节
自动更新❌ 不支持✅ 支持(通过 ON UPDATE CURRENT_TIMESTAMP
NULL 处理NULL 存入 NULL未显式赋值时自动填充当前时间
2038 年问题❌ 不受影响✅ 2038 年后溢出(范围限制)

详细解析

1. 时间范围与存储空间
  • DATETIME

    • 范围:公元 1000 年 ~ 9999 年(跨千年)。
    • 空间:MySQL 5.6.4+ 后固定 5 字节(旧版本 8 字节)。
  • TIMESTAMP

    • 范围:1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC(著名的 2038 年问题)。
    • 空间:固定 4 字节(存储 Unix 时间戳整数)。

⚠️ 2038 年问题
TIMESTAMP 在 2038 年将溢出(类似 Y2K 问题),而 DATETIME 无此风险。


2. 时区行为(最核心区别!)
操作DATETIMETIMESTAMP
写入数据直接存储客户端提交的时间字符串
(无视时区)
将客户端时间转为 UTC 时间存储
读取数据原样返回存储的字符串
(无时区转换)
根据当前会话时区转回本地时间返回
示例:写入 2023-10-01 12:00:00(客户端时区为 UTC+8)
INSERT INTO table (dt_col, ts_col) VALUES ('2023-10-01 12:00:00', '2023-10-01 12:00:00');
操作DATETIME 值TIMESTAMP 值(存储的 UTC)
存储结果2023-10-01 12:00:002023-10-01 04:00:00(UTC)
查询时(会话时区 UTC+8)返回 2023-10-01 12:00:00返回 2023-10-01 20:00:00
查询时(会话时区 UTC-5)返回 2023-10-01 12:00:00返回 2023-10-01 07:00:00

关键结论

  • 若需跨时区统一时间(如国际化系统),用 TIMESTAMP
  • 若需存储绝对时间(如生日、合同签订时间),用 DATETIME

3. 自动更新特性
  • TIMESTAMP 支持自动初始化/更新:
    CREATE TABLE example (
      created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 插入时自动填充当前时间
      updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -- 更新时自动修改
    );
    
  • DATETIME 需手动实现类似功能:
    CREATE TABLE example (
      created DATETIME DEFAULT NULL,
      updated DATETIME DEFAULT NULL
    );
    -- 依赖程序或触发器更新
    

4. NULL 处理差异
  • TIMESTAMP 列未显式赋值时
    • 若未声明 DEFAULT 值,MySQL 会自动填充当前时间(即使插入 NULL)。
    INSERT INTO table (ts_col) VALUES (NULL); -- 实际存入当前时间
    
  • DATETIME
    • 严格按写入值存储(支持 NULL)。

选择建议

✅ 优先用 TIMESTAMP 的场景:
  1. 需要自动记录行创建/修改时间(如 created_at, updated_at)。
  2. 处理跨时区应用(如全球用户的登录时间记录)。
  3. 存储空间敏感(高频写入的大表)。
✅ 优先用 DATETIME 的场景:
  1. 存储超过 2038 年的时间(如历史档案、长期合同)。
  2. 存储与时区无关的绝对时间(如出生日期、事件计划时间)。
  3. 需要完整支持 NULL 语义(明确区分未设置时间)。

经典示例

场景:用户订单表
CREATE TABLE orders (
  id INT PRIMARY KEY,
  order_time DATETIME,      -- 订单生成时间(绝对时间,不受时区影响)
  paid_time TIMESTAMP       -- 支付成功时间(自动记录,支持时区转换)
);

-- 插入数据(北京时间 UTC+8)
INSERT INTO orders (id, order_time, paid_time)
VALUES (1, '2030-12-31 23:59:59', NULL); 

-- 支付成功后更新
UPDATE orders SET paid_time = NOW() WHERE id = 1;
  • order_time:存入 2030-12-31 23:59:59(即使服务器时区变更,值不变)。
  • paid_time
    • 存储为 UTC 时间(如 2030-12-31 15:59:59 UTC)。
    • 查询时根据会话时区转换显示(如 UTC+8 显示为 2031-01-01 00:59:59)。

总结

维度选 DATETIME选 TIMESTAMP
时间范围1000年~9999年 都可选择1970~2038 年内
时区需求存储绝对时间(如生日)需自动时区转换(如用户操作时间)
存储开销不敏感(5 字节)敏感(4 字节)
自动更新不需要需要(如 updated_at)
NULL 处理需要明确存储 NULL可接受自动填充当前时间

💡 终极建议

  • 93% 的场景中 TIMESTAMP 更适合记录时间戳(如 created_at)。
  • 涉及历史或未来超长期时间时,必须用 DATETIME
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值