javascript - 为新的一年计算一个新的日期,同时保持一周中的适当日期(即:星期一)
问题描述
背景:活动策划/管理软件工具
目标:复制前一年的事件 - 并为用户选择事件的开始和结束日期提供一个良好的开端。
假设:这个新事件可能是重复/逐年事件。因此,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')
})
}
对于我们在这里做错的事情以及我们如何解决它,我们将不胜感激。谢谢!
解决方案
这是一个解决方案,它采用未来的开始日期、结束日期和年数,并返回未来的开始和结束日期
- 与原始开始日期在一周的同一天开始
- 在原始开始日期的三天内开始
- 未来开始日期和结束日期之间的天数与原始开始日期和结束日期之间的天数相同
逻辑步骤是:
- 通过将输入年数添加到原始开始日期来近似未来开始日期
- 确定原始开始日期的数字 DOW 与近似的未来日期之间的差异
- 将下表转换为公式:
.
+----------------+-----------------------------------------------+
| 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)
- 从近似的未来日期中减去计算的天数,以确定实际的未来日期
- 确定原始开始日期和结束日期之间的天数差异,并将它们添加到计算的未来开始日期以获得未来结束日期
- 返回计算出的未来开始和结束日期
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>
推荐阅读
- wordpress - 如何在管理订单详细信息中显示自定义产品分类?
- selenium-webdriver - 使用 Specflow RemoteWebDriver 进行并行浏览器测试
- tableau-api - 发布后是否可以在 Tableau 中打开一个新选项卡以进行深入报告
- javascript - 从 Chrome 录制的音频无法在 Safari 上播放
- matlab - 如何在 Matlab 图中找到所有交点?
- html - CSS 代码未正确转换为 SCSS
- prolog - 如何修剪错误的答案?我的代码错了吗?
- python - 将 python 输出保存为 csv
- ruby-on-rails - 如何使用正则表达式匹配 Ruby 中包含特殊字符的重复模式?
- google-cloud-platform - 从 Dataproc 集群访问 GKE 集群中的 Postgres