检查是否有超过两个日期范围重叠

21

我有多个日期范围,想要在JavaScript中检查它们是否重叠。当只有两个范围时,很容易,我使用以下代码:

if(start_times1 <= end_times2 && end_times1 >= start_times2) {}

但是当有超过2个日期范围时,公式是什么?


不是同样的想法吗? - Bucket
但是怎么做呢?我不知道确切的日期数量。可能是2个,也可能是3个或4个。 - Niek Nijland
8个回答

40

你可以使用嵌套的 for 循环和 arguments

function dateRangeOverlaps(a_start, a_end, b_start, b_end) {
    if (a_start <= b_start && b_start <= a_end) return true; // b starts in a
    if (a_start <= b_end   && b_end   <= a_end) return true; // b ends in a
    if (b_start <  a_start && a_end   <  b_end) return true; // a in b
    return false;
}
function multipleDateRangeOverlaps() {
    var i, j;
    if (arguments.length % 2 !== 0)
        throw new TypeError('Arguments length must be a multiple of 2');
    for (i = 0; i < arguments.length - 2; i += 2) {
        for (j = i + 2; j < arguments.length; j += 2) {
            if (
                dateRangeOverlaps(
                    arguments[i], arguments[i+1],
                    arguments[j], arguments[j+1]
                )
            ) return true;
        }
    }
    return false;
}

2
因为你提到了“日期”,所以我在这些函数的名称中加入了“date”一词,但实际上它们适用于任何“数字”范围。 - Paul S.
@PaulS. 感谢您提供的解决方案,它真的为我节省了很多时间! - Kalish
我们如何实现这个?哪里是启动这个的函数调用? - TetraDev
如何将相同重叠日期合并? - ruin3936
在编写代码时,仅仅输入一些代码行而不注释可能不是一个好主意。 - Alex
如果您正在使用现代代码,请改用rest参数:multipleDateRangeOverlaps(...args) { /* ... */ },并将arguments的用法替换为args。请参考链接:@Akashlal https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments - Paul S.

15

这是保罗发布的精炼版本:

  • 添加了过滤器和空值检查,以允许任意数量的条目
  • 更改逻辑使其可应用于数组。例如:[{"from": value, "to": value}]
  • 调整了重叠检查,以允许具有相同结束和开始时间的时间

脚本:

function dateRangeOverlaps(a_start, a_end, b_start, b_end) {
    if (a_start < b_start && b_start < a_end) return true; // b starts in a
    if (a_start < b_end   && b_end   < a_end) return true; // b ends in a
    if (b_start <  a_start && a_end   <  b_end) return true; // a in b
    return false;
}

function multipleDateRangeOverlaps(timeEntries) {
    let i = 0, j = 0;
    let timeIntervals = timeEntries.filter(entry => entry.from != null && entry.to != null && entry.from.length === 8 && entry.to.length === 8);

    if (timeIntervals != null && timeIntervals.length > 1)
    for (i = 0; i < timeIntervals.length - 1; i += 1) {
        for (j = i + 1; j < timeIntervals.length; j += 1) {
                if (
                dateRangeOverlaps(
            timeIntervals[i].from.getTime(), timeIntervals[i].to.getTime(),
            timeIntervals[j].from.getTime(), timeIntervals[j].to.getTime()
                    )
                ) return true;
            }
        }
   return false;
}

你救了我的一天。 - Aakash Bumiya

5
以下代码来自我的项目,也许可以帮助你:

function dateRangeOverlaps(startDateA, endDateA, startDateB, endDateB) {

    if ((endDateA < startDateB) || (startDateA > endDateB)) {
        return null
    }

    var obj = {};
    obj.startDate = startDateA <= startDateB ? startDateB : startDateA;
    obj.endDate = endDateA <= endDateB ? endDateA : endDateB;

    return obj;
}


2

只需使用来自“现代JavaScript日期实用程序库”date-fnsareIntervalsOverlapping函数即可。

您只需将两个日期作为参数传递给函数,它将根据这两个日期是否重叠返回true或false。

示例

请查看其文档中的此示例:

areIntervalsOverlapping(
  { start: new Date(2014, 0, 10), end: new Date(2014, 0, 20) },
  { start: new Date(2014, 0, 17), end: new Date(2014, 0, 21) }
)
//=> true

上面的例子返回true,因为两个日期重叠。请注意Date(2014, 0, 10)中的数字0(第二个参数)代表一月份。
你还可以使用areIntervalsOverlapping函数来检查其他时间间隔(例如同一天内的小时)是否重叠,因为在JavaScript中,一个Date对象也包括小时。
安装方法:
如果您使用Node.js(或任何使用它的框架),只需使用以下命令安装date-fns即可:
npm install date-fns --save

然后在您的JavaScript代码中导入所需的函数,如下:

import { areIntervalsOverlapping } from "date-fns";

当然,date-fns 不仅限于 Node.js。您可以在任何 JavaScript 项目中使用它。

1
为什么我们不使用moment和moment-range?它在所有浏览器中都不受支持吗?

window['moment-range'].extendMoment(moment);

const events1 = [{
    "Date": "05/15/2021",
    "EndTime": "17:00",
    "StartTime": "16:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "18:00",
    "StartTime": "17:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "18:45",
    "StartTime": "17:45"
}
];

const events2 = [{
    "Date": "05/15/2021",
    "EndTime": "17:00",
    "StartTime": "16:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "18:00",
    "StartTime": "17:00"
},
{
    "Date": "05/15/2021",
    "EndTime": "19:45",
    "StartTime": "18:45"
}
];

function checkOverlap(timeSegments) {

    var overlap = timeSegments
        .map(r =>
            timeSegments.filter(q => q != r).map(q =>
                moment.range(
                    moment(q.Date + " " + q.StartTime),
                    moment(q.Date + " " + q.EndTime)
                ).overlaps(
                    moment.range(
                        moment(r.Date + " " + r.StartTime),
                        moment(r.Date + " " + r.EndTime)
                    )
                )
            )
        );

    console.log(overlap.map(x => x.includes(true)).includes(true));
}

checkOverlap(events1);
checkOverlap(events2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/4.0.2/moment-range.js"></script>


甚至可以使用其后继者luxon内置的“Interval”类型。 - Twometer

1

//存储现有日期以进行比较

public multipleExistingDates=[
         {startDate:'02/03/2020 05:00:00',endDate:'02/03/2020 05:30:00'},
         {startDate:02/04/2020 05:00:00'',endDate:'02/05/2020 05:00:00'},]

/比较新日期与现有日期以检查新日期是否与现有日期重叠/

public checkOverlappingDsates(startDate:Date, endDate:Date):boolean{
  return this.multipleExistingDates.some((elem)=>{
       return( !((moment(endDate).diff(moment(elem.startDate))) < 0 || 
              (moment(startDate).diff(moment(elem.endDate))) > 0;})

注意:如果日期重叠,该函数返回true,否则返回false。此外,您需要安装moment进行日期比较。

-1

递归实现并不难。创建一个名为overlap的方法,用于返回两个日期范围之间的重叠部分。然后在您的hasOverlap(list dates)方法中,如果列表中只有两个项,那就简单了,否则请返回hasoverlap(overlap(dates[0], dates[1]), rest of list)


一个“range”总是2D的,而列表则是1D的,但长度可以未知。你有足够的已知条件来完成这个任务,无需使用递归。 - Paul S.

-1
无论使用哪种语言,判断两个日期范围是否重叠的基本逻辑都是相同的:
max(range_1_start, range_2_start) <= min(range_1_end, range_2_end)

在JavaScript语法中,可能看起来像这样:
function doDatesOverlap(start_1,end_1,start_2,end_2){
    return Math.max(start_1,start_2) <= Math.min(end_1,end_2);
}

var start_1 = new Date('01/01/2023');
var end_1 = new Date('01/31/2023');
var start_2 = new Date('01/15/2023');
var end_2 = new Date('02/15/2023');

if(doDatesOverlap(start_1,end_1,start_2,end_2)){
    console.log('They overlap!');
}

这个问题涉及到不止两个日期范围的重叠。 - Niek Nijland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接