使用Mongoose搭配moment-timezones.js时,MongoDB为何将UTC+2转为UTC+0?
解决MongoDB时区转换问题
问题根源
你遇到的UTC+2时间被转成UTC+0存储的问题,原因有两个:
- 你用
moment().format()生成带时区的ISO字符串,但如果Schema中XPBoostExpiration是Date类型,MongoDB会自动将其解析为UTC时间戳的Date对象存储,读取时若未指定时区展示,就会显示为UTC+0时间。 forceServerObjectId: true选项和时间处理无关,它仅用于强制生成服务器端ObjectId,因此添加后无效果。
解决方案
方案一:直接存储Date对象(推荐)
MongoDB存储Date对象时会保留正确的UTC时间戳,读取时再用moment-timezone转换回目标时区:
// 保存时存Date对象 const date = moment().toDate(); console.log(date); playerDataSchema .updateOne( { DiscordID: user.id }, { XPBoost: true, XPBoostExpiration: date } ) .catch(function (err) { console.log(err); }); // 读取时转换为UTC+2时区 playerDataSchema.findOne({ DiscordID: user.id }).then(doc => { // 替换为你的UTC+2时区标识符,比如'Europe/Budapest' const expDate = moment(doc.XPBoostExpiration).tz('Europe/Budapest').format(); console.log(expDate); });
方案二:存储带时区的ISO字符串(Schema字段设为String)
如果需要直接保留时区信息,修改Schema中XPBoostExpiration的类型为String,MongoDB会直接存储原字符串,不做解析转换:
// Schema定义示例 const playerDataSchema = new mongoose.Schema({ DiscordID: String, XPBoost: Boolean, XPBoostExpiration: String // 改为String类型 }); // 保存代码不变,可强制指定UTC+2时区 const date = moment().tz('Europe/Budapest').format(); console.log(date); playerDataSchema .updateOne( { DiscordID: user.id }, { XPBoost: true, XPBoostExpiration: date } ) .catch(function (err) { console.log(err); });
方案三:存储UTC时间戳
直接存储毫秒级时间戳,读取时再转换为对应时区的时间:
// 保存时存时间戳 const timestamp = moment().tz('Europe/Budapest').valueOf(); console.log(timestamp); playerDataSchema .updateOne( { DiscordID: user.id }, { XPBoost: true, XPBoostExpiration: timestamp } ) .catch(function (err) { console.log(err); }); // 读取时转换 playerDataSchema.findOne({ DiscordID: user.id }).then(doc => { const expDate = moment(doc.XPBoostExpiration).tz('Europe/Budapest').format(); console.log(expDate); });
注意:使用
moment().tz()时,需确保已引入对应时区数据,可通过moment.tz.add()添加或使用预打包的时区库。
内容的提问来源于stack exchange,提问作者lulacz TV
相关产品推荐
相关产品推荐

