更新Drizzle(Neon)数据库时区识别错误,新增操作正常的问题咨询
为什么Drizzle更新Neon数据库时会报"time zone 'gmt-0700' not recognized"错误,而插入操作正常?
问题场景
在患者仪表板实现取消预约功能时,点击按钮触发API调用,通过Drizzle的update方法更新预约状态和scheduledAt字段,报错Error: time zone "gmt-0700" not recognized,但使用相同格式的ISO字符串执行insert操作却完全正常。
关键代码片段
报错的更新逻辑
export const updateAppointmentStatus = async ( appointment_id: string, status: "Scheduled" | "Completed" | "Canceled" | "No-Show" ) => { return db .update(schema_management.appointments) .set({ status: status, scheduledAt: new Date().toISOString(), }) .where(eq(schema_management.appointments.id, appointment_id)) .returning(); };
当前表结构的scheduledAt配置
scheduledAt: timestamp('scheduled_at', { mode: 'string' }) .notNull(),
正常工作的插入处理
const apppointment: AppointmentsInterface = { ...body, scheduledAt: new Date(body.scheduledAt).toISOString(), }; await addAppointment(apppointment);
核心原因:Drizzle对update和insert的日期处理逻辑差异
Neon(基于PostgreSQL)要求时区格式为带冒号的标准标识符(如GMT-07:00)或时区名称(如America/Los_Angeles),而new Date().toISOString()生成的YYYY-MM-DDTHH:mm:ss.sssZ格式本身符合标准,问题出在Drizzle的SQL生成逻辑:
- Insert操作:传入ISO字符串时,Drizzle会直接将字符串作为字面量传递给数据库,PostgreSQL能正确解析该格式为带时区的时间戳。
- Update操作:在
set方法中,Drizzle会对字符串类型的日期字段进行隐式转换——将ISO字符串解析为Date对象后,再转换为PostgreSQL时间戳格式,但这个过程中会生成不带冒号的GMT-0700格式,这是PostgreSQL无法识别的时区格式,因此触发报错。
即使你将表结构从{ withTimezone: true, mode: 'date' }改为{ mode: 'string' },Drizzle的update逻辑依然保留了对Date类型的隐式转换逻辑,这就导致了与insert操作的行为差异。
原更新方法的修复方案
无需使用查询后重插的绕路方式,直接让Drizzle将字符串作为字面量传递给数据库即可,推荐使用Drizzle的sql模板字符串:
import { sql } from 'drizzle-orm'; export const updateAppointmentStatus = async ( appointment_id: string, status: "Scheduled" | "Completed" | "Canceled" | "No-Show" ) => { return db .update(schema_management.appointments) .set({ status: status, scheduledAt: sql`${new Date().toISOString()}`, }) .where(eq(schema_management.appointments.id, appointment_id)) .returning(); };
通过sql模板包裹字符串,强制Drizzle直接传递字面量,避免隐式转换生成错误的时区格式。
内容的提问来源于stack exchange,提问作者Kenan Blair
相关产品推荐
相关产品推荐

