使用ExpressJS向MongoDB存储数据时日期自动减1问题
ExpressJS存入MongoDB日期自动减1的解决办法
问题现象
提交的请求体中日期为06/27/2023,但存入MongoDB后变为2023-06-26T18:30:00.000Z,日期自动减1。
请求体示例
{ "name":"Articulation Exam", "location":"IoN Center", "timing":"11:00am", "date":"06/27/2023", "maximum_allowed_participants":100, "active_participants":1 }
数据库存储结果
{ "_id": "6485a0737cd0de176a0c87c0", "name": "Articulation Exam", "location": "IoN Center", "timing": "11:00am", "date": "2023-06-26T18:30:00.000Z", "maximum_allowed_participants": 100, "active_participants": 1, "createdAt": "2023-06-11T10:22:43.046Z", "updatedAt": "2023-06-11T10:22:43.046Z", "__v": 0 }
路由代码
router.route('/post').post((req,res)=>{ const data = { name:req.body.name, location:req.body.location, timing:req.body.timing, date:new Date(req.body.date), maximum_allowed_participants:req.body.maximum_allowed_participants, active_participants:req.body.active_participants } const newRecord = new Events(data); newRecord.save() .then(response=>res.send('A new event "'+response.name+'" has been added Succssfully!')) .catch(err=>res.send(err)); })
Schema定义
const eventSchema = new Schema({ name:{ type:String, required:true, trim:true, minlength:3 }, location:{ type:String, required:true, trim:true, minlength:2 }, timing:{ type:String, required:true, trim:true, }, date:{ type:Date, required:true }, maximum_allowed_participants:{ type:Number, required:true }, active_participants:{ type:Number, required:true } }, { timestamps:true });
原因分析
这是时区差异导致的:
- MongoDB默认以UTC时间存储日期数据。
- 使用
new Date(req.body.date)时,JS会基于服务器本地时区解析06/27/2023(默认视为当天0点),随后自动转换为UTC时间存储。 - 从存储结果
2023-06-26T18:30:00.000Z来看,服务器所在时区为UTC+5:30(印度标准时间),本地时间06/27 00:00转换为UTC就是06/26 18:30,因此数据库中显示转换后的UTC日期。
解决办法
方法1:手动构造UTC日期
拆分输入的日期字符串,用Date.UTC构造UTC时区的当天0点:
router.route('/post').post((req,res)=>{ // 拆分MM/DD/YYYY格式的日期 const [month, day, year] = req.body.date.split('/'); // 构造UTC日期(JS中月份从0开始,需减1) const utcDate = new Date(Date.UTC(year, month - 1, day)); const data = { name:req.body.name, location:req.body.location, timing:req.body.timing, date: utcDate, maximum_allowed_participants:req.body.maximum_allowed_participants, active_participants:req.body.active_participants } const newRecord = new Events(data); newRecord.save() .then(response=>res.send('A new event "'+response.name+'" has been added Succssfully!')) .catch(err=>res.send(err)); })
这样存储的日期会是2023-06-27T00:00:00.000Z,对应本地时区的06/27。
方法2:用日期处理库(如moment.js)
使用moment.js便捷处理时区,确保解析为UTC日期:
- 安装moment:
npm install moment - 修改路由代码:
const moment = require('moment'); router.route('/post').post((req,res)=>{ const data = { name:req.body.name, location:req.body.location, timing:req.body.timing, // 按MM/DD/YYYY解析并转为UTC日期 date: moment(req.body.date, 'MM/DD/YYYY').utc().toDate(), maximum_allowed_participants:req.body.maximum_allowed_participants, active_participants:req.body.active_participants } const newRecord = new Events(data); newRecord.save() .then(response=>res.send('A new event "'+response.name+'" has been added Succssfully!')) .catch(err=>res.send(err)); })
方法3:读取时转换为本地时区
如果不需要修改存储逻辑,可在读取数据时将UTC时间转换为本地时区显示:
// 示例:读取记录后转换日期 Events.findById('6485a0737cd0de176a0c87c0') .then(event => { // 将UTC日期转为本地时区的MM/DD/YYYY格式字符串 const localDate = event.date.toLocaleDateString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit' }); event.localDate = localDate; res.send(event); })
内容的提问来源于stack exchange,提问作者Gokul
相关产品推荐
相关产品推荐

