JavaScript 检查时间范围是否重叠

JavaScript check if time ranges overlap

本文关键字:是否 重叠 范围是 范围 检查 时间 JavaScript      更新时间:2023-09-26

例如,我有一个包含 2 个对象的数组(myObject1 和 myObject2 如)。现在,当我添加第三个对象时,我将检查时间范围是否重叠。实际上,我不知道如何以高性能的方式做到这一点。

var myObjectArray = [];
var myObject1 = {};
myObject1.startTime = '08:00';
myObject1.endTime = '12:30';
...
var myObject2 = {};
myObject2.startTime = '11:20';
myObject2.endTime = '18:30';
...
myObjectArray.push(myObject1);
myObjectArray.push(myObject2);

假设我们有一些间隔

const INTERVALS = [
  ['14:00', '15:00'],
  ['08:00', '12:30'],
  ['12:35', '12:36'],
  ['13:35', '13:50'],
];

如果我们想将新的间隔添加到此列表中,我们应该检查新间隔是否与其中一些不重叠。

您可以循环低谷间隔并检查新的间隔是否与其他间隔重叠。请注意,在比较间隔时,如果您确定日期对象与可以将时间转换为数字的日期相同,则不需要 Date 对象:

function convertTimeToNumber(time) {
  const hours = Number(time.split(':')[0]);
  const minutes = Number(time.split(':')[1]) / 60;
  return hours + minutes;
}

两种情况下,间隔不重叠:

    之前 (a c && b
a          b
|----------|
             c          d
             |----------| 
    在 where (a> c && a> d) && (b>
  1. c && b> d):
             a          b
             |----------|
c          d
|----------| 

因为总是c < d,所以说不重叠间隔的条件是(a < c && b < c) || (a > d && b > d)就足够了,因为总是a < b,所以说这个条件等价于就足够了:

b < c || a > d

对这个条件的否定应该给我们一个重叠区间的条件。根据德摩根定律,它是:

b >= c && a <= d

请注意,在这两种情况下,间隔都不能相互"接触",这意味着 5:00-8:00 和 8:00-9:00 将重叠。如果要允许它,条件应该是:

b > c && a < d

至少需要考虑 5 种重叠间隔的情况:

a          b
|----------|
      c          d
      |----------| 
      a          b
      |----------|
c          d
|----------| 
      a          b
      |----------|
c                    d
|--------------------|
a                    b
|--------------------|
      c          d
      |----------|
a          b
|----------|
c          d
|----------|

带有额外添加和排序间隔函数的完整代码如下:

    const INTERVALS = [
      ['14:00', '15:00'],
      ['08:00', '12:30'],
      ['12:35', '12:36'],
      ['13:35', '13:50'],
    ];

    function convertTimeToNumber(time) {
      const hours = Number(time.split(':')[0]);
      const minutes = Number(time.split(':')[1]) / 60;
      return hours + minutes;
    }
    // assuming current intervals do not overlap
    function sortIntervals(intervals) {
      return intervals.sort((intA, intB) => {
        const startA = convertTimeToNumber(intA[0]);
        const endA = convertTimeToNumber(intA[1]);
        const startB = convertTimeToNumber(intB[0]);
        const endB = convertTimeToNumber(intB[1]);
        if (startA > endB) {
          return 1
        }
        if (startB > endA) {
          return -1
        }
        return 0;
      })
    }

    function isOverlapping(intervals, newInterval) {
      const a = convertTimeToNumber(newInterval[0]);
      const b = convertTimeToNumber(newInterval[1]);
      for (const interval of intervals) {
        const c = convertTimeToNumber(interval[0]);
        const d = convertTimeToNumber(interval[1]);
        if (a < d && b > c) {
          console.log('This one overlap: ', newInterval);
          console.log('with interval: ', interval);
          console.log('----');
          return true;
        }
      }
      return false;
    }
    function isGoodInterval(interval) {
      let good = false;
      if (interval.length === 2) {
        // If you want you can also do extra check if this is the same day
        const start = convertTimeToNumber(interval[0]);
        const end = convertTimeToNumber(interval[1]);
        if (start < end) {
          good = true;
        }
      }
      return good;
    }
    function addInterval(interval) {
      if (!isGoodInterval(interval)) {
        console.log('This is not an interval');
        return;
      }
      if (!isOverlapping(INTERVALS, interval)) {
        INTERVALS.push(interval);
        // you may also want to keep those intervals sorted
        const sortedIntervals = sortIntervals(INTERVALS);
        console.log('Sorted intervals', sortedIntervals);
      }
    }

    // --------------------------------------
    const goodIntervals = [
      ['05:31', '06:32'],
      ['16:00', '17:00'],
      ['12:31', '12:34']
    ];
    let goodCount = 0;
    for (const goodInterval of goodIntervals) {
      if (!isOverlapping(INTERVALS, goodInterval)) {
        goodCount += 1
      }
    }
    console.log('Check good intervals: ', goodCount === goodIntervals.length);
    // --------------------------------------
    const ovelappingIntervals = [
      ['09:30', '12:40'],
      ['05:36', '08:50'],
      ['13:36', '13:37'],
      ['06:00', '20:00'],
      ['14:00', '15:00']
    ]
    let badCount = 0;
    for (const badInterval of ovelappingIntervals) {
      if (isOverlapping(INTERVALS, badInterval)) {
        badCount += 1
      }
    }
    console.log('Check bad intervals: ', badCount === ovelappingIntervals.length);
    // --------------------------------------
    addInterval(goodIntervals[0])

你可以尝试这样的事情:

var timeList = [];
function addTime() {
  var startTime = document.getElementById("startTime").value;
  var endTime = document.getElementById("endTime").value;
  if (validate(startTime, endTime)){
    timeList.push({
      startTime: startTime,
      endTime: endTime
    });
    print(timeList);
    document.getElementById("error").innerHTML = "";
    }
  else
    document.getElementById("error").innerHTML = "Please select valid time";
}
function validate(sTime, eTime) {
  if (+getDate(sTime) < +getDate(eTime)) {
    var len = timeList.length;
    return len>0?(+getDate(timeList[len - 1].endTime) < +getDate(sTime) ):true;
  } else {
    return false;
  }
}
function getDate(time) {
  var today = new Date();
  var _t = time.split(":");
  today.setHours(_t[0], _t[1], 0, 0);
  return today;
}
function print(data){
  document.getElementById("content").innerHTML = "<pre>" + JSON.stringify(data, 0, 4) + "</pre>";
}
<input type="text" id="startTime" />
<input type="text" id="endTime" />
<button onclick="addTime()">Add Time</button>
<p id="error"></p>
<div id="content"></div>

将 moment-js 与矩范围一起使用(损坏的引用)

测试示例:

const range1 = moment.range(a, c);
const range2 = moment.range(b, d);
range1.overlaps(range2); // true

查看 https://github.com/rotaready/moment-range#overlaps 中的更多示例

请注意,要

使上面的代码正常工作,也许您首先要执行以下操作:

<script src="moment.js"></script>
<script src="moment-range.js"></script>
window['moment-range'].extendMoment(moment);

网页代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-range/2.2.0/moment-range.min.js"></script>

JavaScript 代码

var range  = moment.range(new Date(year, month, day, hours, minutes), new Date(year, month, day, hours, minutes));
var range2 = moment.range(new Date(year, month, day, hours, minutes), new Date(year, month, day, hours, minutes));
range.overlaps(range2); // true or flase

非常简洁的解决方案,momentjs带有大量的日期和时间实用程序。

使用 JavaScript Date() 对象来存储时间,然后比较它们,如果 object1 的结束时间大于 object2 的开始时间,则它们是重叠的。您可以使用运算符>比较它们。

date1.getTime() > date2.getTime()

此处给出的演示

Date 对象的用法

要确定时间范围是否与其他时间范围重叠,您可以同时使用moment.js库和moment-range库。

首先安装moment-jsmoment-range假设您有一个包含示例对象的 INTERVALS 数组:

const INTERVALS = [
    { START: 0, END: 10 },
    { START: 12, END: 30 },
    ...
]

您可以使用以下函数:

const validateIntervalOverlaps = () => {
if (INTERVAL_START && INTERVAL__END) {
  const timeInterval = moment.range(moment(INTERVAL_START), moment(INTERVAL_ENDS))
  const overlappingInterval = INTERVALS.find(intervalItem => {
    const interval = moment.range(moment(intervalItem.START), moment(intervalItem.END))
    return timeInterval.overlaps(interval)
  })
  return overlappingInterval
}

}

接下来,您可以执行需要对重叠间隔执行的操作:)F.e. 确定它是否存在或以任何其他方式使用它。祝你好运!

这里有一些可能有效的方法。

// check if time overlaps with existing times
for (var j = 0; j < times.length; j++) {
        let existing_start_time = moment(this.parseDateTime(this.times[j].start_time)).format();
        let existing_end_time = moment(this.parseDateTime(this.times[j].end_time)).format();
        // check if start time is between start and end time of other times
        if (moment(start_time).isBetween(existing_start_time, existing_end_time)) {
            times[i].error = 'Time overlaps with another time';
            return false;
        }
        // check if end time is between start and end time of other times
        if (moment(end_time).isBetween(existing_start_time, existing_end_time)) {
            times[i].error = 'Time overlaps with another time';
            return false;
        }
}

https://momentjs.com/

您可以通过尝试将时间范围合并到现有时间范围来检查是否存在重叠,如果合并后时间范围的总计数减少,则存在重叠。

我发现了以下文章,可能有助于处理合并范围

  • 合并具有重叠值的数组
  • 合并范围