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

Calculate a new date, for a new year, while maintaining the appropriate day of the week (ie: Monday)

上下文:一个事件Planning/Management软件工具

目标: 复制一年前的活动 - 并为用户提供选择活动开始和结束日期的先机。

假设:这个新事件可能是一个repeat/year-over-year事件。因此,2018 年 10 月的活动将克隆到 2019 年 10 月。

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

预期结果:

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

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

可能的逻辑: 我认为预期的结果 可以 通过获取月份、月份的星期和星期的日期来实现 - 并以此为基础构建新的事件日期,为新的一年。

考虑因素: 如果可能的话,我想使用 Moment.js

Use Case / Actual Design

Expected Result / Examples

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

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')
  })  
}

The resulting, incorrect dates:

对于我们在这里做错的任何帮助以及我们如何解决它,我们将不胜感激。谢谢!

这是一个采用开始日期、结束日期和未来年数以及returns未来开始和结束日期的解决方案

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

逻辑步骤是:

  1. 通过将输入的年数与原始开始日期相加来估算未来的开始日期
  2. 确定原始开始日期的数字 DOW 与大概的未来日期之间的差异
  3. 将下面的table转换成公式:

.

+----------------+-----------------------------------------------+
| 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. Return 计算的未来开始和结束日期

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>