繁体   English   中英

从 JavaScript 中的选定日期范围中获取非选定日期范围

[英]Get non-selected date ranges from the selected date ranges in JavaScript

我有一个日期范围数组( selectedRanges ),它显示了主要日期范围之间成员的分配日期。 我想知道他/她未分配的日期范围。 请参考以下示例。

mainDateRange = ['01-01-2020', '14-06-2020'];

selectedRanges = [
 ['03-01-2020','04-01-2020'],
 ['03-01-2020','05-01-2020'],  //overlapping dates
 ['11-01-2020','13-01-2020'],
 ['01-02-2020','20-02-2020'],
 ['15-03-2020','18-03-2020'],
 ['06-01-2020','06-01-2020'],  //date ranges will not be ordered
 ['03-01-2020','04-01-2020']
]; //dates that the member has work assigned

所需 output

excludedRanges = [
 ['01-01-2020','02-01-2020'],
 ['07-01-2020','10-01-2020'],
 ['14-01-2020','31-01-2020'],
 ['21-02-2020','14-03-2020'],
 ['19-03-2020','14-06-2020']
];  //shows all the unassigned periods(ranges)

selectedRanges日期范围将具有随机顺序的范围,也可能具有重复和重叠的日期。

我搜索了很多,一无所获。 我只能获得未选择的日期,而不是一个范围。 请帮忙。

谢谢

有趣的问题,我将提出一种通过执行以下操作来实现这种期望行为的方法:

  • 将所有字符串日期转换为日期对象。
  • 使用开始日期和结束日期按升序对selectedRanges数组进行排序。 此排序步骤对于查找日期范围差距至关重要。
  • 添加在mainDateRange之间移动的“移动光标”日期以查找缺失的范围并将其添加到 output 数组。

在开始日期计算之前,我们需要一些辅助函数。 我在日期 object 和您拥有的字符串格式 ( dd-mm-yyyy ) 之间来回向 go 添加了两个函数。 请注意,如果您使用 Moment.js 之类的东西,您可能不需要这两个帮助程序function ,但我不会对您的项目施加额外的依赖。

function stringToDate(stringDate) {
    const parts = stringDate.split('-').map((p) => parseInt(p));
    parts[1] -= 1;
    return new Date(...parts.reverse());
}
function dateToString(date) {
    return `${('0' + date.getDate()).slice(-2)}-${('0' + (date.getMonth() + 1)).slice(-2)}-${date.getFullYear()}`;
}

我还添加了一个排序器 function 确保范围以升序方式排序(首先是较小的范围)。

function dateRangeSorter(a, b) {
    if (a[0] < b[0]) return -1;
    else if (a[0] > b[0]) return 1;
    if (a[1] < b[1]) return -1;
    else if (a[1] > b[1]) return 1;
    return 0;
}

现在我们对 go 的计算很好,这是一个代码片段,将在最后记录 output。

 // data const output = []; const oneDayInMs = 24 * 60 * 60 * 1000; const mainDateRange = ['01-01-2020', '14-06-2020']; const selectedRanges = [ ['03-01-2020','04-01-2020'], ['03-01-2020','05-01-2020'], ['11-01-2020','13-01-2020'], ['01-02-2020','20-02-2020'], ['15-03-2020','18-03-2020'], ['06-01-2020','06-01-2020'], ['03-01-2020','04-01-2020'] ]; // helpers function stringToDate(stringDate) { const parts = stringDate.split('-').map((p) => parseInt(p)); parts[1] -= 1; return new Date(...parts.reverse()); } function dateToString(date) { return `${('0' + date.getDate()).slice(-2)}-${('0' + (date.getMonth() + 1)).slice(-2)}-${date.getFullYear()}`; } function dateRangeSorter(a, b) { if (a[0] < b[0]) return -1; else if (a[0] > b[0]) return 1; if (a[1] < b[1]) return -1; else if (a[1] > b[1]) return 1; return 0; } // transform into date and sort const mainDateRangeAsDates = mainDateRange.map(stringToDate); const selectedRangesAsDates = selectedRanges.map((range) => (range.map(stringToDate))).sort(dateRangeSorter); // start at the beginning of the main date range let movingDate = mainDateRangeAsDates[0]; // loop through the selected ranges selectedRangesAsDates.forEach(([startDate, endDate]) => { // if there's a gap, add it to the output if (movingDate < startDate) { output.push([ dateToString(movingDate), dateToString(new Date(startDate.getTime() - oneDayInMs)) ]); } // move the cursor date to one day after the end of current rage movingDate = new Date(endDate.getTime() + oneDayInMs); }); // if there is a gap at the end, add it as well if (movingDate < mainDateRangeAsDates[1]) { output.push([ dateToString(movingDate), dateToString(mainDateRangeAsDates[1]) ]); } console.log(output);

使用了类似的方法: 如何确保较大范围的每个数字都在一些较小的范围内?

将所有字符串转换为日期。 按范围的最小值排序。
将最小 position 向前移动,直到找到一个间隙,然后推送到 res 数组。
将范围从最后一个最小值推到最大值(如果存在)

 mainDateRange = ['01-01-2020', '14-06-2020']; selectedRanges = [ ['03-01-2020', '04-01-2020'], ['03-01-2020', '05-01-2020'], //overlapping dates ['11-01-2020', '13-01-2020'], ['01-02-2020', '20-02-2020'], ['15-03-2020', '18-03-2020'], ['06-01-2020', '06-01-2020'], //date ranges will not be ordered ['03-01-2020', '04-01-2020'] ]; //dates that the member has work assigned function gapFinder(mainDateRange, selectedRanges) { const dateToInt = a => new Date(a.split('-').reverse().join('-')) const intToDate = a => new Date(a).toISOString().slice(0, 10).split('-').reverse().join('-') // convert to numbers selectedRanges = selectedRanges.map(r => r.map(dateToInt)) // presort ranges selectedRanges.sort(([a, ], [b, ]) => a - b) let [min, max] = mainDateRange.map(dateToInt) const res = [] for (const [x, y] of selectedRanges) { if (min > max) break if (min < x) res.push([min, x.setDate(x.getDate() - 1)]) min = Math.max(min, y.setDate(y.getDate() + 1)) } if (min <= max) res.push([min, max]) return res.map(r => r.map(intToDate)) } console.log(JSON.stringify(gapFinder(mainDateRange,selectedRanges))) selectedRanges.push(['11-06-2020', '13-06-2020']) console.log(JSON.stringify(gapFinder(mainDateRange,selectedRanges)))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM