TypeORM使用EntityManager查询PostgreSQL时日期格式返回异常
TypeORM 0.2.45 对接PostgreSQL 原生查询日期格式不一致解决方法
两种查询返回结果差异的核心逻辑:
- Repository的
find()等内置查询方法会读取实体类的列定义元数据,针对标记为date类型的字段,直接保留数据库返回的YYYY-MM-DD原始字符串格式 EntityManager.query()执行原生SQL时,不会走实体元数据映射逻辑,直接使用底层node-postgres驱动的默认解析规则,会自动将PostgreSQL的date类型值转换为JavaScript Date对象,受服务端时区影响就会出现带时区偏移的时间戳,甚至日期差1天的问题。
可根据项目场景选择对应方案:
方案1:全局配置驱动解析规则(推荐,全项目统一生效)
在NestJS的TypeORM根配置(TypeOrmModule.forRoot()入参)中,透传node-postgres驱动的自定义类型解析器,覆盖date类型的默认转换逻辑,直接返回原始字符串值:
import { TypeOrmModule } from '@nestjs/typeorm'; import { types as pgTypes } from 'pg'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'postgres', host: '你的数据库地址', port: 5432, username: '账号', password: '密码', database: '库名', entities: [/* 你的实体类,比如Invoice */], synchronize: false, // 新增以下配置 extra: { types: { getTypeParser: (oid: number, format: any) => { // PostgreSQL中date类型的固定OID为1082 if (oid === 1082) { return (value: string) => value; // 直接返回原始YYYY-MM-DD字符串,不转Date } // 其余数据类型保持默认解析逻辑 return pgTypes.getTypeParser(oid, format); } } } }) ] }) export class AppModule {}
配置完成后,所有查询(包括Repository内置方法、EntityManager原生query)返回的date类型字段都会统一为YYYY-MM-DD格式字符串,不会再出现自动转Date的问题。该配置仅修改纯日期类型的解析规则,不会影响timestamp、timestamptz等时间类型的原有解析逻辑。
方案2:原生SQL中手动转换字段类型(适配个别查询场景)
如果不想修改全局配置,仅需要在个别原生查询中拿到纯日期字符串,可以在SQL语句中将对应date字段强转为text类型,驱动识别为文本类型就不会做Date转换:
const em = getManager(); const q: Invoice[] = await em.query(` SELECT *, date::text AS date, dueDate::text AS dueDate FROM invoice `); return q;
该方案的缺点是每个原生查询都需要手动对日期字段做转换,字段较多时维护成本高。
方案3:查询结果二次格式化(兜底方案)
拿到原生查询的返回结果后,遍历数据手动将对应日期字段格式化为YYYY-MM-DD字符串,格式化时需要注意校正时区偏移,避免出现日期差1天的问题,该方案维护成本最高,仅作为兜底选择。
内容的提问来源于stack exchange,提问作者Toby Boulton
相关产品推荐
相关产品推荐

