DayJS+React+MongoDB时区问题:日期显示异常解决方案咨询
问题描述
我在MongoDB中用Date.now存储createdAt字段,代码如下:
createdAt: { type: Date, default: Date.now }
MongoDB中存储的记录为:
createdAt: 2023-02-01T01:39:03.377+00:00
在React中获取记录后,用DayJS执行以下代码格式化日期:
dayjs(createdAt).format('DD/MM/YY')
出现错误:实际为2023年2月1日的记录,格式化后显示为1月31日,这对财务记录造成冲突。服务器未设置时区,使用MongoDB Atlas云服务。
我的MongoDB聚合查询在请求2月信息时返回结果正确,但React端显示出错,聚合语句如下:
db.purchases.aggregate([ { $match: { "detail.category._id": ObjectId("63bf4d0b10dfcae061b6eab0") } }, { $unwind: "$detail" }, { $group: { _id: "$detail.category._id", total: { $sum: "$total" }, totalProductPurchases: { $sum: "$detail.quantity" }, purchasesCount: { $sum: 1 }, purchases: { $push: { $cond: [ { $and: [ { $eq: [{ $year: "$createdAt" }, 2023] }, { $eq: [{ $month: "$createdAt" }, 2] }, { $gte: [{ $dayOfMonth: "$createdAt" }, 1] }, { $lte: [{ $dayOfMonth: "$createdAt" }, 31] } ] }, { purchaseId: "$_id", month: { $month: "$createdAt" }, isoWeek: { $isoDayOfWeek: "$createdAt" }, dayOfMonth: { $dayOfMonth: "$createdAt" }, createdAt: "$createdAt", total: "$total", subtotal: "$subtotal", tax: "$tax", discount: "$discount", totalBeforeTax: "$totalBeforeTax", createdAt: "$createdAt", paymentType: "$paymentType" }, false ] } }, product_counts: { $push: { product: "$detail.name", count: "$detail.quantity" } }, } }, { $unwind: "$product_counts" }, { $group: { _id: "$product_counts.product", ProductPurchasesNumber: { $sum: "$product_counts.count" }, purchases: { $first: "$purchases"}, totalProductPurchases: { $first: "$totalProductPurchases"}, total: { $first: "$total"}, purchasesCount: { $first: "$purchasesCount"} } }, { $sort: { count: -1 } }, { $limit: 3 }, { $group: { _id: null, top3Products: { $push: { product: "$_id", ProductPurchasesNumber: "$ProductPurchasesNumber" } }, total: { $first: "$total" }, totalProductPurchases: { $first: "$totalProductPurchases" }, purchasesCount: { $first: "$purchasesCount" }, purchases: { $first: "$purchases" } } }, { $addFields: { purchasesArrayLength: { $size: "$purchases" }, filteredPurchases: { $filter: { input: "$purchases", as: "purchase", cond: { $ne: [ "$$purchase", false ] } } } }, }, { $project: { purchases: 0 } } ])
解决方法
1. 强制DayJS使用UTC时区格式化
MongoDB存储的是UTC时间,DayJS默认用本地时区解析,导致日期偏移。如果业务以UTC日期为准,直接用UTC模式格式化:
import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' dayjs.extend(utc) // 用UTC时区格式化日期 dayjs(createdAt).utc().format('DD/MM/YY')
2. 转换为业务所需的特定时区
如果财务记录需要对应特定时区的日期(比如用户所在地时区),引入DayJS时区插件明确转换:
import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' import timezone from 'dayjs/plugin/timezone' dayjs.extend(utc) dayjs.extend(timezone) // 示例:转换为东八区(北京时间) dayjs(createdAt).tz('Asia/Shanghai').format('DD/MM/YY')
3. 在MongoDB聚合阶段提前格式化日期
既然聚合查询能正确识别日期,可以在聚合过程中直接生成格式化后的日期字符串,前端直接使用即可:
在聚合的$group阶段的purchases对象中,新增格式化字段:
formattedCreatedAt: { $dateToString: { format: "%d/%m/%y", date: "$createdAt", timezone: "UTC" // 也可指定业务需要的时区,如"Asia/Shanghai" } }
4. 统一服务器与数据库时区(谨慎操作)
可以在MongoDB Atlas连接字符串中指定时区,或在服务器代码中设置默认时区为UTC,确保存储与读取的时区一致性,但此方式可能影响其他业务逻辑,需评估后操作。
内容的提问来源于stack exchange,提问作者OscarDev
相关产品推荐
相关产品推荐

