【问题标题】:Date Range Comparison in Array数组中的日期范围比较
【发布时间】:2018-02-05 15:26:18
【问题描述】:

我正在尝试比较数组中的日期是否重叠但有问题。用户可以添加任意数量的日期,我需要检查它们以确保没有重叠。

日期数组(开始和结束日期在它们之间加上(-):

dates (4) ["02/07/2018-02/07/2018", "02/05/2018-02/07/2018", "02/06/2018-02/06/2018", "02/08/2018-02/08/2018"]

我的代码:

        function CheckOverlappingDates(dates) {
        var startDate = []; 
        var endDate = [];
        var isOverlap;
        for (var i = 0; i < dates.length; i++) {
            var split = dates[i].split('-');  // just split once
            startDate.push(new Date(split[0]).toLocaleDateString());
            endDate.push(new Date(split[1]).toLocaleDateString());

            for (var x = 0; x < startDate.length; x++) {
                if (startDate[x] >= startDate[x + 1] && startDate[x + 1] <= endDate[x + 1]) {
                    isOverlap = true;
                } else {
                    isOverlap = false;
                }
            }

        }

    }

我将它们分成 startdate 和 enddate ,如下所示

但我的函数不比较多个日期范围。

【问题讨论】:

  • 将它们转换为纪元毫秒。然后比较。
  • This: new Date(split[0]).toLocaleDateString() 然后使用 startDate[x] &gt;= startDate[x + 1] 比较结果字符串不是一个好主意。原始字符串的解析是依赖于实现的,就像 toLocaleString 的结果一样,没有理由相信结果是正确或可靠的,而且许多人相信它们不会。

标签: javascript arrays date date-comparison


【解决方案1】:

比较日期字符串时,您可以将它们转换为日期对象或将它们保留为字符串并使用localeCompare。不要使用内置的日期解析器,因为它不可靠。一个 2 行函数可以将格式设置为字符串或转换为日期,字符串可能更有效,但比较日期的代码更少。

要查看一个范围数组是否有重叠,需要将每个范围与数组中它之后的范围进行比较。没有必要与之前的人核对,因为这已经完成了。

不清楚应该如何处理重叠范围,因此该函数只返回一个字符串数组,其中包含“范围 A 与范围 B 重叠”。它还假设范围是包容性的,因此 02/05/2018-02/07/2018 与 02/07/2018-02/08/2018 重叠。

例如

var dates = ["02/07/2018-02/07/2018", "02/05/2018-02/07/2018", "02/06/2018-02/06/2018", "02/08/2018-02/08/2018"];

// Assume array of ranges in format mm/dd/yyyy-mm/dd/yyyy
// Return array of overlapping ranges
function inRange(dates) {

  // Parse date string to Date
  function fn(s) {
    var b = s.split(/\D/);
    return new Date(b[2], b[0]-1, b[1]);
  }
  
  // Return true if range a overlaps range b
  // where range is string in format mm/dd/yyyy-mm/dd/yyyy
  // Overlaps if start or end of b are inside a, or
  // a is wholly inside b
  function overlaps(a, b) {
    a = a.split('-').map(fn);
    b = b.split('-').map(fn);
    return (b[0] >= a[0] && b[0] <= a[1]) || // b start in a
           (b[1] >= a[0] && b[1] <= a[1]) || // b end in a
           (b[0] <= a[0] && b[1] >= a[1]);   // b encloses a
  }
  
  // Array for overlapping ranges
  var overlappers = [];
  var max = dates.length - 1;

  dates.forEach(function(date, i) {
  
    // Don't test last as already tested
    if (i < max) {
    
      // Only test from this element to end of array
      for (var j = i+1; j <= max; j++) {
      
        // If overlaps, add to overlappers array
        if (overlaps(date, dates[j])) {
          overlappers.push(date + ' overlaps ' + dates[j]);
        }
      }
    }
  });
  return overlappers;
}

console.log(inRange(dates));

简单的解析器期望日期是有效的。如果需要检查,则需要在解析器中增加一行代码,并且需要在主函数中处理无效日期。

【讨论】:

    【解决方案2】:

    您可以使用for循环检查。

    var dates = ["02/07/2018-02/07/2018", "02/05/2018-02/07/2018", "02/06/2018-02/06/2018", "02/08/2018-02/08/2018"];
    var overlaps = checkOverlaps(dates);
    
    console.log("overlaps", overlaps);
    
    var dates1 = ["02/07/2018-02/07/2018", "02/08/2018-02/10/2018", "02/19/2018-02/20/2018", "02/21/2018-02/21/2018"];
    var nonoverlaps = checkOverlaps(dates1);
    
    console.log("nonoverlaps", nonoverlaps);
    
    var dates2 = ["02/07/2018-02/07/2018", "02/07/2018-02/10/2018"]; /* 2nd range starts on the end of the first range */
    var overlaps2 = checkOverlaps(dates2);
    
    console.log("overlaps", overlaps2);
    
    function checkOverlaps(dates) {
      var o = false;
    
      for (var key1 in dates) {
        var cDateArr = dates[key1].split("-");
        var d1 = new Date(cDateArr[0]);
        var d2 = new Date(cDateArr[1]);
    
        for (var key2 in dates) {
    
          //make sure not comparing to own self
          if (key1 != key2) {
            var cDateArrB = dates[key2].split("-");
            var dB1 = new Date(cDateArrB[0]);
            var dB2 = new Date(cDateArrB[1]);
    
            if (
              (d1 < dB1 && d2 > dB1) ||
              (d1 < dB2 && d2 > dB2) ||
              cDateArr[0] == cDateArrB[0] ||
              cDateArr[0] == cDateArrB[1] ||
              cDateArr[1] == cDateArrB[0] ||
              cDateArr[1] == cDateArrB[1]
            ) {
              o = true;
            }
          }
        }
      }
    
      return o;
    }

    【讨论】:

    • 您不应该使用 for..in 来遍历数组,因为可能存在您不期望的可枚举属性,并且可能不会按照您期望的顺序访问属性任何一个。最后,您不应该对日期字符串使用内置解析器,它们是出了名的不可靠。
    猜你喜欢
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多