从 DataTime 类型修改开始
目前的所有时间字段都是这样定义的:
created_at DateTime @default(now())
这是一种不推荐的写法(尤其当你的应用有全球用户、需要 处理不同时区时)。
为什么需要修改?
- Prisma 默认把
DateTime映射为 PostgreSQL 的TIMESTAMP(不带时区,timestamp without time zone)。 - 这会导致时区混乱、夏令时问题、不同服务器/客户端时间偏移等 Bug。
- 最佳实践是统一使用
TIMESTAMPTZ(带时区的时间戳),它在数据库内部始终以 UTC 存储,是处理多时区应用的标准做法。
推荐的修改方式
将所有时间字段修改为以下形式:
// 创建时间
created_at DateTime @default(now()) @db.Timestamptz(6)
// 更新时间(推荐使用 @updatedAt 自动更新)
updated_at DateTime @updatedAt @db.Timestamptz(6)
// 其他业务时间字段(例如事件开始时间、截止时间等)
event_time DateTime? @db.Timestamptz(6)
published_at DateTime? @db.Timestamptz(6)
完整修改建议示例:
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
timezone String @default("UTC") @db.Text
created_at DateTime @default(now()) @db.Timestamptz(6)
updated_at DateTime @updatedAt @db.Timestamptz(6)
// 其他模型类似处理
}
修改后的步骤
-
修改
schema.prisma文件中所有DateTime字段,加上@db.Timestamptz(6)。 -
生成迁移:
npx prisma migrate dev --name add_timestamptz(或者如果你是第一次大改,可以用
prisma db push测试) -
重新生成 Prisma Client:
npx prisma generate
注意事项
- 现有数据:修改后,如果表中已有数据,Prisma 迁移通常能自动处理(因为只是类型转换),但建议在生产环境前先在测试库验证。
- 精度:
(6)表示微秒精度,是目前最常用的设置。如果你对精度要求不高,也可以用(3)(毫秒)。 - @updatedAt:强烈推荐对
updated_at使用@updatedAt,它会自动在更新记录时填充当前时间。 - 默认值:
@default(now())仍然保留,它在数据库层面会使用当前 UTC 时间。
总结推荐:
- 所有时间戳字段 → 统一改成
DateTime @default(now()) @db.Timestamptz(6)(或@updatedAt)。 - 存入数据库时永远是 UTC。
- 显示给用户时,再结合
user.timezone使用AT TIME ZONE转换为本地时间。
Prisma 时区字段
在 Prisma 中定义用户的时区字段(IANA 时区名称,如 Asia/Shanghai、America/New_York),推荐写法如下:
推荐定义方式(Prisma Schema)
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
/// 用户的 IANA 时区
timezone String @default("UTC") @db.Text
// 或者限制长度(更节省空间)
// timezone String @default("UTC") @db.VarChar(64)
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)
}
说明:
- 类型使用
String:Prisma 中对应 PostgreSQL 的字符串类型。 - @default("UTC"):强烈推荐设置默认值为
'UTC',避免空值导致的问题。 - @db.Text:映射到 PostgreSQL 的
TEXT类型(推荐,无长度限制,简单清晰)。 - @db.VarChar(64):如果你想更严格控制长度也可以使用(时区名称最长通常不会超过 50 个字符)。