为新的一年计算一个新的日期,同时保持一周中合适的日期(即:星期一)



上下文:事件规划/管理软件工具

目标:克隆前一年的事件,并在选择开始&活动的结束日期。

假设:这个新事件很可能是一个重复/逐年发生的事件。因此,2018年10月的活动将被克隆到2019年10月。

示例:正在克隆的事件的开始日期为:2016年10月20日星期四,结束日期:2016年11月3日星期四(包括事件的设置和拆卸日期)

预期结果:

  • 保持日期范围内的天数。(14天)
  • 保持一周中的某一天。(两者均为周四)

代码应返回一个新的开始日期:2019年10月17日星期四和结束日期:2019年10日31日星期四

可选:另一个可接受的日期范围可能是:2019年10月24日星期四,结束日期为2019年11月7日

可能的逻辑:我认为通过抓住当月、当月周和该周的日期,并为新的一年构建新的事件日期,可以实现预期的结果

注意事项:如果可能的话,我想使用Moment.js库

用例/实际设计

预期结果/示例

当前代码:这是我们目前的代码,但没有返回预期的结果。似乎只是减去了一天,而不考虑年份差异。

const today = moment();
const thisYear = today.format('YYYY');
const old_start = moment('2018-10-08');
const old_end = moment('2018-08-12');
// if in same year, use current dates
if (thisYear === old_start.format('YYYY')) {
console.log({
start: new_start.format('YYYY-MM-DD'),
end: new_end.format('YYYY-MM-DD')
})
} else {  
console.log({
start: new_start.year(thisYear)
.isoWeek(old_start.isoWeek())
.isoWeekday(old_start.isoWeekday())
.format('YYYY-MM-DD'),
end: new_end.year(thisYear)
.isoWeek(old_end.isoWeek())
.isoWeekday(old_end.isoWeekday())
.format('YYYY-MM-DD')
})  
}

由此产生的错误日期:

如果我们在这里做错了什么,以及如何解决问题,我们将不胜感激。谢谢!

这里有一个解决方案,它获取开始日期、结束日期和未来的年数,并返回

  1. 在一周中与原始开始日期相同的日期开始
  2. 在原始开始日期的三天内开始
  3. 未来开始日期和结束日期之间的天数与原始开始日期和终止日期之间的相同

逻辑步骤为:

  1. 通过将输入年份添加到原始开始日期来近似未来的开始日期
  2. 确定原始开始日期的数字DOW与大致未来日期之间的差值
  3. 将下表转换为公式:

+----------------+-----------------------------------------------+
| DOW difference | Days to subtract from approximate future date |
+----------------+-----------------------------------------------+
|      -6        |        1                                      |
|      -5        |        2                                      |
|      -4        |        3                                      |
|      -3        |       -3                                      |
|      -2        |       -2                                      |
|      -1        |       -1                                      |
|       0        |        0                                      |
|       1        |        1                                      |
|       2        |        2                                      |
|       3        |        3                                      |
|       4        |       -3                                      |
|       5        |       -2                                      |
|       6        |       -1                                      |
+----------------+-----------------------------------------------+

我把它编码为:

Math.abs(dowDiff) < 4 ? dowDiff : dowDiff + 7 * -Math.sign(dowDiff, daysAdd)
  1. 从近似的未来日期中减去计算的天数,以确定实际的未来日期
  2. 确定原始开始日期和结束日期之间的天数差,并将它们添加到计算的未来开始日期中以获得未来结束日期
  3. 返回计算的未来开始和结束日期

const getFutureDates = (start, end, years) => {
const dStart = moment(start);
const dStartFuture = dStart.clone().add(years || 1, 'years');
const dowDiff = dStartFuture.day() - dStart.day();
const daysSub = Math.abs(dowDiff) < 4 ? dowDiff : dowDiff + 7 * -Math.sign(dowDiff, daysAdd);
dStartFuture.subtract(daysSub, 'days');
const days = moment(end).diff(dStart, 'days');
const dEndFuture = dStartFuture.clone().add(days, 'days');
return {
start: dStartFuture,
end: dEndFuture
};
}
const tests = [
{start: '2011-08-10', end: '2011-08-20', years: 8},
{start: '2017-08-09', end: '2017-08-19', years: 2},
{start: '2014-08-06', end: '2014-08-16', years: 5},
];
tests.forEach(({start, end, years}) => {
const format = (s, e) => `${moment(s).format('YYYY-MM-DD')} to ${moment(e).format('YYYY-MM-DD')}`;
const {start: fStart, end: fEnd} = getFutureDates(start, end, years);
console.log(`${format(start, end)} => ${format(fStart, fEnd)}`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.min.js"></script>

最新更新