You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 20:50:29