Prisma传递非ISO8601参数问题:如何匹配timestamp with timezone字段?
问题背景
数据库列采用timestamp with timezone(其中一张表为timestampz(6)),存储的时间格式为"2023-05-25 10:26:32.809521 +00:00"。但使用Prisma查询时遇到问题:
- 传入Date对象或日期字符串,Prisma会将参数转换为
"params": "[\"2023-03-25 10:26:32.809 UTC\",0]"格式,不仅时区写法改变,还会截断微秒为毫秒 - 原生SQL验证结果:
SELECT * FROM audit.record_version where audit.record_version.ts = '2023-05-25T10:26:32.809Z';→ 无匹配结果SELECT * FROM audit.record_version where audit.record_version.ts = '2023-05-25 10:26:32.809521 +00:00';→ 查询到数据
- 当前使用的where子句:
"ts": { "equals": row.ts }
其中row.ts为Date对象,即使直接传入符合存储格式的字符串,也会被Prisma修改格式并截断精度。
解决办法
- 用原生参数化查询绕过Prisma自动转换
直接使用Prisma的$queryRaw编写原生SQL,将完整的时间字符串作为参数传入,避免Prisma的自动格式化:
const exactTime = "2023-05-25 10:26:32.809521 +00:00"; const result = await prisma.$queryRaw` SELECT * FROM audit.record_version WHERE ts = ${exactTime} `;
这种方式还能避免SQL注入风险,比直接拼接字符串更安全。
- 在Prisma Schema中指定微秒精度
打开schema.prisma文件,将对应字段的类型设置为DateTime(6),明确匹配数据库的timestampz(6)类型:
model RecordVersion { id Int @id @default(autoincrement()) ts DateTime(6) @db.Timestamp(6, true) // (6)指定微秒精度,true对应带时区类型 }
修改完成后重新生成Prisma客户端:npx prisma generate,此后Prisma处理Date对象时会保留6位微秒精度,不会随意截断。
- 手动格式化时间字符串
如果你的Date对象本身携带微秒数据(注意:JS原生Date仅支持毫秒精度,需额外存储微秒信息才有效),可以手动将其转换为数据库兼容的格式:
function formatToDbTime(date) { const isoStr = date.toISOString(); // 输出格式:2023-05-25T10:26:32.809521Z return isoStr.replace('T', ' ').replace('Z', ' +00:00'); } const formattedTs = formatToDbTime(row.ts); const result = await prisma.record_version.findMany({ where: { ts: formattedTs } });
问题原因说明
UTC与+00:00的等价性
2023-05-25T10:26:32.809Z和2023-05-25 10:26:32.809 +00:00的时区含义完全等价,查询不到数据的核心原因是精度不匹配:数据库存储的是6位微秒,而Prisma传递的是3位毫秒,数值不一致导致无匹配结果。Prisma的默认处理逻辑
Prisma默认会将Date对象转换为UTC格式字符串,且仅保留3位毫秒精度。一方面是因为JavaScript的Date对象本身仅支持毫秒精度,另一方面是Prisma默认的DateTime类型精度为毫秒,未指定时会自动截断微秒。
内容的提问来源于stack exchange,提问作者Michael D Johnson
相关产品推荐
相关产品推荐

