【问题标题】:How to find dates intersections / conflicts in an array of dates using JavaScript如何使用 JavaScript 在日期数组中查找日期交集/冲突
【发布时间】:2022-11-01 18:23:38
【问题描述】:

我有一个活动,其中列出了将要发生的研讨会。每个研讨会可以有多个会议。接口看起来像:

interface Workshop {
    ...
    meetings: WorkshopMeeting[];
}

interface WorkshopMeeting {
    id: number;
    startDate: Date;
    endDate: Date;
}

我的最终对象有一个 Workshop 数组,例如:

const event = {
  // ... other data
  workshops: [] as Workshop[]
}

我需要的是找出所有研讨会会议之间是否有任何互动。

例如,我的活动有 2 个工作坊,第一个工作坊计划于 29/03/2022 14:00 开始,并于 29/03/2022 18:00 结束,而我的第二个工作坊计划于 29/03 开始/2022: 15:00 到 29/03/2022: 20:00 结束。在这种情况下,研讨会 2 的会议与研讨会 1 的会议同时发生。

我正在尝试创建一个算法来查找这些日期冲突,但我没有取得好的进展。

我尝试了一些循环,但找不到比较逻辑

【问题讨论】:

    标签: javascript algorithm date


    【解决方案1】:

    Moment JS 可以帮助你:

    const date1 = [moment("2016-12-06 11:00"), moment("2016-12-06 12:00")];
    const date2 = [moment("2016-12-06 10:00"), moment("2016-12-06 13:00")];
    
    const range  = moment.range(date1);
    const range2 = moment.range(date2);
    
    // has overlapping
    if(range.overlaps(range2)) {
        if((range2.contains(range, true) || range.contains(range2, true)) && !date1[0].isSame(date2[0]))
        alert("time range 1 is completely conflict with time range 2 and vice versa");
      else
        alert("time range 1 is partially conflict with time range 2 and vice versa");
    

    【讨论】:

    • 这真的很有帮助。我正在研究一种算法。等我完成了,我会分享的。谢谢!
    【解决方案2】:

    这是一个使用这样的内部图表的解决方案:

       09     10     11     12     13     14     15     16     17     18     19     20  
                                          (------------- 1 ------------)
                                                 (----------------- 2 ---------------)
       (----- 3 -----)
                     (----- 4 ------)
                            (------------ 5 ------------)
    

    然后收集那里的关键时间(任何事件停止或开始的地方),这里是911121314151820 ,将它们分组为一对,例如9 - 1111 - 12、...18 - 20,并为每一个找到在周期结束之前开始和在其开始之后结束的事件。然后它过滤列表以返回具有多个事件的列表:

    // utility functions
    const inPairs = (xs) => xs .slice (1) .map ((x, i) => [xs [i], x])
    
    const uniq = (xs) => [... new Set (xs)]
    
    // main function
    const overlaps = (events) =>
      inPairs (uniq (events .flatMap ((w) => [w .startDate, w .endDate])) .sort ())
        .map (([start, end]) => ({
          start, 
          end, 
          events: events.filter (e => e .startDate < end && e.endDate > start) .map (e => e .id) 
        }))
        .filter (({events}) => events .length > 1)
    
    
    // sample data
    const meetings = [{id: 1, startDate: '2022-03-29T14:00:00', endDate: '2022-03-29T18:00:00'}, {id: 2, startDate: '2022-03-29T15:00:00', endDate: '2022-03-29T20:00:00'}, {id: 3, startDate: '2022-03-29T09:00:00', endDate: '2022-03-29T11:00:00'}, {id: 4, startDate: '2022-03-29T11:00:00', endDate: '2022-03-29T13:00:00'}, {id: 5, startDate: '2022-03-29T12:00:00', endDate: '2022-03-29T16:00:00'}]
    
    // demo
    const conflicts = overlaps (meetings) 
    
    // display
    conflicts .forEach (({start, end, events}) => console .log (`${start} - ${end}: events: ${events .join (', ')}`))

    inPairs['a', 'b', 'c', 'd'] 之类的内容转换为[['a', 'b']. ['b', 'c'], ['c', 'd']]

    uniq简单地收集元素数组的唯一元素。

    我们的主要功能overlaps首先收集事件列表的所有开始和结束日期,找到唯一元素,对它们进行排序,然后使用inPairs将该列表转换为句点数组。我们将这些映射到对象中,找到与该时期重叠的所有事件。最后,我们将它们过滤到包含多个事件的那些。

    这使用 ISO-8601 字符串日期而不是 Date 对象。如果您想使用实际日期,您将需要找到另一种方法来创建唯一集并进行事件过滤。这些并不难,但在调用此函数之前转换为这种格式可能会更容易。

    这并不能解决您的外部问题,但会为您提供一个冲突列表以及每个冲突中的事件。

    【讨论】:

    • 这是一个有趣的方法。谢谢你的提示。我会尽力。
    【解决方案3】:
     function findOverlap(startTime: Moment, endTime: Moment, source:{id:number, startTime:Date,endTime:Date}[]) {
    return source.reduce((list, cur) => {
      if (
        moment(cur.startTime).valueOf() < endTime.valueOf()
        && moment(cur.endTime).valueOf() > startTime.valueOf()
      ) {
        if (moment(cur.endTime).valueOf() < endTime.valueOf()) {
          if (startTime.valueOf() > moment(cur.startTime).valueOf()) {
            list.push(
              moment(cur.endTime).valueOf() - startTime.valueOf(),
            );
          } else {
            list.push(
              moment(cur.endTime).valueOf() - moment(cur.startTime).valueOf(),
            );
          }
        } else if (startTime.valueOf() > moment(cur.startTime).valueOf()) {
          list.push(
            endTime.valueOf() - startTime.valueOf(),
          );
        } else {
          list.push(
            endTime.valueOf() - moment(cur.startTime).valueOf(),
          );
        }
      }
      return list;
    }, [] as number[]);
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-12
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      相关资源
      最近更新 更多