新增 schema 时, date 会乱跳
发布于 1年前 作者 Knovour 585 次浏览

您好,想请问一下,最近在写个功能為使用者每次新增一笔资料后,还要设一个三天后过期的资料,最后再写个 setInterval 每一分钟检查一次,如果过期就标记并作其他后续处理。但不知為何,用 mongoose 设好的 schema 的日期有机会会产生跳掉的情形,而且是日期提前了,像今天 create_at 是 10 号,但 expire_date 却跑到 9 号去,造成资料一新增马上就过期,有时则是 create_at 提前了,请问这是怎么一回事?谢谢。

更正,create_at 的资料没问题,是 expire_date 算完后时间反而提前了,抱歉误导了。

node 版本是 0.8.23 mongoose: 3.8.2 mongodb: 2.0.4

//model

var Data = new Schema({
  create_at: { type: Date, default: Date.now },
  expire_date: { type: Date, default: (new Date().setDate(new Date().getDate() + 3)) },
  expired: false
});


mongoose.model('Data', DataSchema);
// check out date

setInterval(function() {
  Data.find(function(err, data) {
    if(!err) {
      var length = data.length;
      for(var i =0; i < length; i++) {
        if(!data[i].expired && new Date() > data[i].expire_date) {
          data[i].expired = true;
          data[i].save();
        }
      }
    }
  });
}, 60000);
11 回复

new Date().getDate() + 3,三天之后不是这样写吧,假设已经是30号呢?建议先转成秒数,在次基础上加上24 * 3600 * 3,然后再转成日期。

这样可以的吧,超出来的日期Date会自动算到月份上

@nighca 试了下,你说得对。我是c语言的思维:)javascript偶尔一用。 Date.now,不用加括号么?now是个函数吧。还有Date.now()返回的也是毫秒数,并非是Date对象。

你说的10号变9号逻辑上讲应该不会,10号变9号只是你随便举的例子?实际出错的日期没有什么规律么。

另外,不如把两个date先用var声明一下: var create_at = new Date(); var expire_date = new Date(); expire_date.setDate(create_at.getDate() + 3); 这样可以在声明Data之前加个打印调试一下。

@xuduo35 不是随便举,是今天真实发生的,时光倒流其实现在也才出现两次,但也不该出现就是,通常是倒回一到二天。

"expire_date": ISODate("2014-02-09T11:15:14.301Z"),
"create_at": ISODate("2014-02-10T08:49:40.565Z") 

Date.now 跟 new Date() 是一样的,只是后者可以用 getDate、setDate 那些函式

@Knovour 从逻辑上讲我看不出什么问题了,也许是其他地方改了,你这里的代码毕竟只是一个片段。我估计未必是这段代码出错。 可以在新增记录成功的callback里直接比较create_at和expire_date,如果记录建好就出错,那么记个log。确定是这里出错或者排除这里出错以后再看。

http://blog.darkthread.net/post-2013-06-25-json-date-timezone-issue.aspx

目前时光倒流能找到的原因最接近的大概是这个

@xuduo35 Date.now 在 mongoose 的宣告中不用加括号。

总觉得你这句有问题 expire_date: { type: Date, default: (new Date().setDate(new Date().getDate() + 3)) }, 如果这个Schema需要的是一个Date的对象,那么default后面返回值是setDate的返回值。javascript里面setDate返回的只是调整过的一个毫秒数。

你这里create_at默认值是函数,而expire_date是值,在这个文件被require的时候(定义模型时)已经求值了! expire_date默认值改成:function() {return new Date().setDate(new Date().getDate() + 3);}试试。 更好的办法是在Schema加个动态方法,在真正创建文档的时候调用:

Data.methods.setExpire = function() {
    this.expire_date = new Date().setDate(new Date(this.create_at).getDate()+3)
}

原来如此,看来是我对 default 的理解有误,谢谢你的解释。

@xuduo35 是的,虽然是毫秒数,但依然是 Date 资料格式,这是可以正常取值的。

回到顶部