JavaScript 检查时间范围是不是重叠

Posted

技术标签:

【中文标题】JavaScript 检查时间范围是不是重叠【英文标题】:JavaScript check if time ranges overlapJavaScript 检查时间范围是否重叠 【发布时间】:2016-06-30 21:21:06 【问题描述】:

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

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);

【问题讨论】:

所以如果只有 2 个条目,您不想检查重叠时间? 他们总是在同一天吗? 是的,都在同一天!每次将新对象推送到数组之前,我都会检查 【参考方案1】:

你可以试试这样的:

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>

【讨论】:

验证方法不正确:validate('23:00','01:31');显示假【参考方案2】:

将moment-js 与moment-range 一起使用(参考失效)

测试示例:

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);

HTML 代码

<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 带有大量的日期和时间实用程序。

【讨论】:

非常感谢您的回答。我的问题是要使用的框架已定义,而 moment-js 不在其中。有没有其他智能解决方案可以做到这一点?谢谢! 嗯 .. 未捕获的 TypeError:moment.range 不是函数 如何让它工作?... UPD .:ups,我忘记了 'var'。所有作品【参考方案3】:

假设我们有一些间隔

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
a          b
|----------|
             c          d
             |----------| 
    在 where (a > c && a > d) && (b > c && b > d) 之后:
             a          b
             |----------|
c          d
|----------| 

因为总是c &lt; d,所以说不重叠区间的条件是(a &lt; c &amp;&amp; b &lt; c) || (a &gt; d &amp;&amp; b &gt; d)就足够了,因为总是a &lt; b,所以说这个条件相当于:

b < c || a > d

否定这个条件应该给我们一个重叠间隔的条件。基于De Morgan's laws 是:

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])

【讨论】:

验证方法不正确:isGoodInterval(['23:00','01:31']);显示假 如果您可以使用此方法更改搜索正确答案的人的方法: function isGoodInterval(interval) let good = false; if (interval.length === 2) good = Date.parse("1-1-2000 " + interval[0]) > Date.parse("1-1-2000 " + interval[1]); 返回好; 这是因为它应该是同一天。间隔 23-01 是另一天。【参考方案4】:

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

date1.getTime() > date2.getTime()

演示给here

Usage of Date object

【讨论】:

【参考方案5】:

这里有一些可行的方法。

// 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/

【讨论】:

【参考方案6】:

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

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

Merge arrays with overlapping values merge-ranges

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于JavaScript 检查时间范围是不是重叠的主要内容,如果未能解决你的问题,请参考以下文章

检查两个日期期间是不是重叠[重复]

检查表格的时间重叠?

检查时间范围重叠,守望者问题 [SQL]

Javascript随机定位的Div而不重叠它们

在情节提要中设置时,UISearchBar 不显示范围栏

如何检查时间跨度是不是与其他时间跨度重叠[重复]