Prisma、Drizzle 的时间类型都会存储为 UTC 时间,JS 时间对象转换 SQL 也会基于 UTC 。应在数据库存 UTC,展示层转本地时区。
为什么时间要存储为 UTC
数据库应保持 UTC 时区存储,优点:
- 数据库存 UTC,避免时区混乱,展示层再转本地时区
- 多服务器部署时,每台机器可能时区不同,这样有利于始终保持一致
一律使用 ORM 框架处理时间
正常来说,把数据库的时区设置为 UTC ,就可以使数据库的时间处理跟 ORM 一致。
但有些数据库环境不方便配置时区,这时候如果把数据库本身的 CURRENT_TIMESTAMP 和 ORM 混用,就会出现时间混乱的情况。
一律使用 ORM 框架处理时间即可,比如 Drizzle 定义 schema 时使用 $defaultFn 这种不会实际影响数据库迁移的语法:
create_time: datetime("create_time").notNull().$defaultFn(() => new Date()),
update_time: datetime("update_time").notNull().$defaultFn(() => new Date()).$onUpdateFn(() => new Date()),
显式接收前端传入的时间字段时(如可供前端设置的活动开始时间、文章发布时间等),也要转换为标准的 UTC 时间,供 ORM 框架处理,转换为 JS 的 Date 对象,并最终以 UTC 时区存入。
历史数据处理
对之前存储 +8 时区的时间的数据,可以写脚本统一调整一下。
使用 MySQL 的内置函数 CONVERT_TZ() 将时间从东八区转换为 UTC 时间。以下是 SQL 语句示例:
UPDATE collection
SET create_time = CONVERT_TZ(create_time, '+08:00', '+00:00'),
update_time = CONVERT_TZ(update_time, '+08:00', '+00:00'),
publish_time = CONVERT_TZ(publish_time, '+08:00', '+00:00');
UPDATE diary
SET create_time = CONVERT_TZ(create_time, '+08:00', '+00:00'),
update_time = CONVERT_TZ(update_time, '+08:00', '+00:00'),
publish_time = CONVERT_TZ(publish_time, '+08:00', '+00:00');
