Javascript 检查日期是否与定期日期匹配

Javascript 检查日期是否与定期日期匹配,javascript,node.js,date,datetime,momentjs,Javascript,Node.js,Date,Datetime,Momentjs,我有一个包含日期的date变量和一个包含数字数组的interval变量。interval数组中的每个数字表示一个日期,该日期是通过将所述数字添加到前一日期的天数中获得的。例如: 如果日期等于2016-09-01并且间隔等于[15,15,20],则产生的日期将是2016-09-16,2016-10-01,2016-10-21,2016-11-06,等等 我想检查给定的日期是否与该模式匹配。为了做到这一点,我尝试使用,这正是我想要的.every()函数,但重复数字的间隔似乎不起作用([15,15,2

我有一个包含日期的
date
变量和一个包含数字数组的
interval
变量。
interval
数组中的每个数字表示一个日期,该日期是通过将所述数字添加到前一日期的天数中获得的。例如:

如果
日期
等于
2016-09-01
并且
间隔
等于
[15,15,20]
,则产生的日期将是
2016-09-16
2016-10-01
2016-10-21
2016-11-06
,等等

我想检查给定的日期是否与该模式匹配。为了做到这一点,我尝试使用,这正是我想要的
.every()
函数,但重复数字的间隔似乎不起作用(
[15,15,20]
将被解析为
[15,20
])。我怎样才能做到这一点,无论是使用矩重现还是使用不同的库

以下是使用矩重现的所需输出:

const now = moment();
const date = moment("2016-09-10", "YYYY-MM-DD");

console.log(date.recur().every([18, 18, 57]).days().matches(now));

你试图做的事情的累积性质有点棘手

也许有更好的方法,但我认为只要你的时间间隔列表不太大,这种方法就行得通

主要的观点是,如果你在寻找一个累计的时间间隔,比如说
[2,10,11]
,那么你将寻找每2,12,23,25,35,46等。这相当于在累加器总和的固定时间间隔内寻找三个不同的日期——在本例中是23。因此,您只需将矩的
every()
用于三种情况中的每种情况和单个间隔

例如,如果您有:

const now = moment();
const date = moment("2016-10-22", "YYYY-MM-DD");
const interval = [18, 18, 57]

// sum of the intervals -- i.e. the main interval (93)
const main_int = interval.reduce( (prev, curr) => prev + curr );

// an array of days for each small interval
const dates = interval.map(i  => moment(date.add(i ,'days')))

// moment mutates the original so this results in 
// [ moment("2016-11-09T00:00:00.000"),
//   moment("2016-11-27T00:00:00.000"),
//   moment("2017-01-23T00:00:00.000") ]

// Now see if any of these days matches the main interval

const match = dates.some(d => d.recur().every(main_int).days().matches(now))

以一种非常笨拙的方式,您试图做的是根据您的序列生成新的累积日期,然后查看它是否在某个点与测试日期匹配

下面使用了moment.js,但实际上并不需要它。即时功能可以在两个单独的函数中用大约10行代码替换

/*@param{Date}sequenceStart-序列的开始
**@param{Array}序列-区间序列
**@param{Date}Date-用于比较的日期
*/
函数插入顺序(sequenceStart、sequence、date){
//复制开始日期,以便不影响原始日期
var s=力矩(起动顺序);
//以合适的格式获取测试日期
var d=时刻(日期).format('yyyyymmdd');
var i=0;
做{
//调试
console.log(s.format('yyyyymmdd')+''+d)
//如果日期匹配,则返回true
if(s.format('YYYYMMDD')==d){
返回true;
}
//如果不匹配,请在序列中添加下一个值
s、 添加(序列[i++%sequence.length],'day');
//如果超过测试日期,则停止

}while(s.format('yyyyymmdd')如果需要,您可以使用@Mark\M所描述的类似方法,而不必使用
时刻重现

第一步是确定给定日期和开始日期之间的天数:
moment(endDate).diff(startDate,'days');

然后,为间隔数组中的每个条目创建自开始日期起天数的累计总计数组:

function sumSoFar(nums) {
   return nums.reduce((sums, num) => {
       const prevSum = last(sums) || 0;
       return sums.concat(num + prevSum);
   }, []);
}

// ...

const sums = sumSoFar(interval);
最后,整个间隔数组的和只是该列表中的最后一个条目,因此我们可以通过取天数差模间隔和来找出它匹配的间隔列表中的哪个条目。如果这是
0
,或者
sums
数组中的一个条目,则日期匹配该间隔。如果不是,则不匹配

以下是我提出的完整代码:

const startDate=力矩('2016-09-01');
常数间隔=[15,15,20];
常量last=(arr)=>arr[arr.length-1];
常量和=(nums)=>nums.reduce((acc,num)=>acc+num,0);
功能sumSoFar(nums){
返回nums.reduce((总和,num)=>{
const prevSum=最后一次(总和)| | 0;
返回和。concat(num+prevSum);
}, []);
}
常数有效期=[时刻('2016-09-16')、时刻('2016-10-01')、时刻('2016-10-21')、时刻('2016-11-05');
函数有效(起始日期、间隔、日期){
常数天=时刻(日期).diff(开始日期,'天');
常数和=sumSoFar(间隔);
持续剩余天数=最后天数的百分比(总和);
return remainingDays==0 | | sums.indexOf(remainingDays)>=0;
}
validDates.forEach(d=>console.log(isValid(startDate,interval,d));

即使没有重复,我也不认为
每一个
都能满足你的需求。它与累计天数不匹配。例如[15,20]每15天和每20天(15,20,30,40)匹配一次,但不是15,然后35,然后50,等等。累计匹配真的是你想要的吗?正如Mark_M所说,
[15,15,20]
不是15天,然后是15天,然后是20天。它是每15天一次,从开始的20天一次,所以从2016-09-01开始,你会得到2016-09-16,2016-09-21,2016-10-01,2016-10-11,2016-10-16,等等。所以
[15,15]
只指定了15天的间隔两次。查看.every(第340行),使用数组值作为属性名将输入数组转换为对象。因此重复的值实际上会被忽略。您指定的是序列,因此可能需要一个新方法。啊,@Mark_M是正确的。
.every()的行为
似乎不是我想要的,现在我再看一眼。我需要一个累积匹配,是的。这正是我需要的,是的。唯一的区别是我忘了提到我需要无限期地循环遍历间隔数组,因为它们是一个重复的东西,但是在你回答之后应该很容易实现。谢谢,但这不会重复序列(虽然不确定是否需要)。嘿@RobG-显然,我可能在这里错了,但我认为这就是
each(main_int)
所做的。它应该检查数组中的任何日期是否与
recur()匹配。each()
这确实重复了序列。公平地说,这是一种有趣的方法。