1

我想找到与输入日期范围重叠的所有可能的日期范围组合。例如,如果用户输入 2013/01/10 到 2013/01/25 并且我有以下日期范围:

2013/01/08 to 2013/01/10
2013/01/09 to 2013/01/15
2013/01/10 to 2013/01/20
2013/01/18 to 2013/01/27
2013/01/14 to 2013/01/19
2013/01/19 to 2013/01/25
2013/01/14 to 2013/01/26
2013/01/10 to 2013/01/26

我想找到与输入日期( 2013/01/10 到 2013/01/25 )重叠的上述日期的所有可能组合。

与输入日期重叠的日期范围的两个示例是:

{2013/01/09 to 2013/01/15, 2013/01/14 to 2013/01/26}
{2013/01/09 to 2013/01/15, 2013/01/14 to 2013/01/19, 2013/01/19 to 2013/01/25}

我没有列出与输入日期范围重叠的所有可能日期范围!
我想找到涵盖输入日期范围所有天数的日期范围组合!如果您看两个示例,我将日期范围组合为涵盖输入日期的所有天数!
我不想用输入日期范围检查一个日期 两个发现如果日期范围涵盖输入日期的所有天数或不!,我想结合日期范围来查找涵盖所有天数的所有可能的日期范围组合输入日期范围。
我想要一种算法来查找涵盖输入日期范围的所有日期的所有可能的日期组合。有没有解决这个问题的快速算法?

4

3 回答 3

1

2013-01-09 to 2013-01-15如果可以找到,我不确定为什么会从列表中丢失,2013-01-09 to 2013-01-15但是您可以根据需要在下面修改此类

$range = [
        new DateManager("2013/01/08", "2013/01/10"),
        new DateManager("2013/01/09", "2013/01/15"),
        new DateManager("2013/01/10", "2013/01/20"),
        new DateManager("2013/01/18", "2013/01/27"),
        new DateManager("2013/01/14", "2013/01/19"),
        new DateManager("2013/01/19", "2013/01/25"),
        new DateManager("2013/01/14", "2013/01/26"),
        new DateManager("2013/01/10", "2013/01/26")
];

$find = new DateManager("2013/01/10", "2013/01/25");

foreach($range as $date) {
    $find->overlap($date) && print($date->getRange() . PHP_EOL);
}

输出

2013/01/09 to 2013/01/15 
2013/01/10 to 2013/01/20 
2013/01/14 to 2013/01/19 
2013/01/19 to 2013/01/25 

班级

class DateManager {
    private $start, $end;

    function __construct($start, $end, $format = "Y/m/d") {
        $this->start = $start instanceof DateTime ? $start : DateTime::createFromFormat($format, $start);
        $this->end = $end instanceof DateTime ? $end : DateTime::createFromFormat($format, $end);
    }

    function getStart() {
        return $this->start;
    }

    function getEnd() {
        return $this->end;
    }

    function getRange($format = "Y/m/d") {
        return sprintf("%s to %s ", $this->start->format($format), $this->end->format($format));
    }

    function between(DateManager $date) {
        return $date->getStart() >= $this->getStart() && $this->getEnd() <= $date->end;
    }

    function overlap(DateManager $date) {
        return (($date->getStart() >= $this->getStart() || $date->getEnd() > $this->getStart()) && $this->getEnd() >= $date->getEnd());
    }
}
于 2013-07-05T12:12:18.093 回答
1

将两个(开始,结束)日期转换为系统时间(从 70 年 1 月 1 日开始,步长 = 1 秒),然后 - 以步长 = 24 * 60 * 60 运行循环。如果需要,将每个值解码为可打印形式。

于 2013-07-05T16:11:23.233 回答
0

I added a couple more data items to make it more interesting:

$start = strtotime('2013/01/10');
$end = strtotime('2013/01/25');
$range[0]['start'] = "2013/01/08";
$range[0]['end'] = "2013/01/10";
$range[1]['start'] = "2013/01/09";
$range[1]['end'] = "2013/01/15";
$range[2]['start'] = "2013/01/10";
$range[2]['end'] = "2013/01/20";
$range[3]['start'] = "2013/01/18";
$range[3]['end'] = "2013/01/27";
$range[4]['start'] = "2013/01/14";
$range[4]['end'] = "2013/01/19";
$range[5]['start'] = "2013/01/19";
$range[5]['end'] = "2013/01/25";
$range[6]['start'] = "2013/01/14";
$range[6]['end'] = "2013/01/26";
$range[7]['start'] = "2013/01/10";
$range[7]['end'] = "2013/01/26";
$range[8]['start'] = "2013/01/9";
$range[8]['end'] = "2013/01/15";
$range[9]['start'] = "2013/01/13";
$range[9]['end'] = "2013/01/19";
$heads = array();
$tails = array();
$combos = array();
$h = 0;
foreach ($range as $key => $value){
    $r1 = strtotime($value['start']);
    $r2 = strtotime($value['end']);
    if ($r1 <= $start && $r2 >= $end){
        $combos[] = $key;
    } elseif($r1 <= $start && $r2 > $start) {
        $heads[$h]['r1'] = $r1;
        $heads[$h]['r2'] = $r2;
        $heads[$h]['seq'] = $key;
        $h++;
    } elseif($r1 > $start && $r1 < $end && $r1 < $r2) {
        $tails[$key]['r1'] = $r1;
        $tails[$key]['r2'] = $r2;
        $tails[$key]['seq'] = $key;
    }
}
while (count($tails) > 0){
    $heads2 = array();
    $tails2 = array();
    $h2 = 0;
    foreach ($heads as $key1 => $value1){
        foreach ($tails as $key2 => $value2){
            if (($value1['r1'] < $value2['r1']) && ($value1['r2'] >= $value2['r1']) && ($value1['r2'] < $value2['r2'])){
                $seq = $value1['seq'].':'.$value2['seq'];
                //keep tail alive, but don't change key
                $tails2[$key2]['r1'] = $value2['r1'];
                $tails2[$key2]['r2'] = $value2['r2'];
                $tails2[$key2]['seq'] = $key2;
                if ($value2['r2'] >= $end){
                    $combos[] = $seq;
                } else {
                    $heads2[$h2]['r1'] = $value1['r2'];
                    $heads2[$h2]['r2'] = $value2['r2'];
                    $heads2[$h2]['seq'] = $seq;
                    $h2++;
                }
            }
        }
    }
    $heads = $heads2;
    $tails = $tails2;
}

The array $combos contains a sequence of array keys seperated by colons, referencing the array keys of the original array. Here's a possible way to display the output:

$html = '';
foreach ($combos as $key => $value){
    $p = '<p>';
    $seqs = explode(':', $value);
    foreach ($seqs as $key2 => $value2){
        $p .= $range[$value2]['start'].' - '.$range[$value2]['end'].'; ';
    }
    $html .= substr($p, 0, -2).'</p>';
}
echo $html;

This displays the following:

2013/01/10 - 2013/01/26
2013/01/09 - 2013/01/15; 2013/01/14 - 2013/01/26
2013/01/10 - 2013/01/20; 2013/01/18 - 2013/01/27
2013/01/10 - 2013/01/20; 2013/01/19 - 2013/01/25
2013/01/10 - 2013/01/20; 2013/01/14 - 2013/01/26
2013/01/9 - 2013/01/15; 2013/01/14 - 2013/01/26
2013/01/09 - 2013/01/15; 2013/01/14 - 2013/01/19; 2013/01/18 - 2013/01/27
2013/01/09 - 2013/01/15; 2013/01/14 - 2013/01/19; 2013/01/19 - 2013/01/25
2013/01/09 - 2013/01/15; 2013/01/13 - 2013/01/19; 2013/01/18 - 2013/01/27
2013/01/09 - 2013/01/15; 2013/01/13 - 2013/01/19; 2013/01/19 - 2013/01/25
2013/01/9 - 2013/01/15; 2013/01/14 - 2013/01/19; 2013/01/18 - 2013/01/27
2013/01/9 - 2013/01/15; 2013/01/14 - 2013/01/19; 2013/01/19 - 2013/01/25
2013/01/9 - 2013/01/15; 2013/01/13 - 2013/01/19; 2013/01/18 - 2013/01/27
2013/01/9 - 2013/01/15; 2013/01/13 - 2013/01/19; 2013/01/19 - 2013/01/25
于 2013-07-05T11:32:33.447 回答