PHP объединяет два отдельных конфликтующих диапазона дат в уникальные пары

Установите один:

  1. 2014-04-05 до 2014-06-27
  2. 2014-06-28 до 2014-10-19

Установите два:

  1. 2014-04-05 до 2014-05-02
  2. 2014-05-03 до 2014-05-31
  3. 2014-06-01 до 2014-10-19

Что мне нужно это для вывода:

  1. 2014-04-05 до 2014-05-02
  2. 2014-05-03 до 2014-05-31
  3. 2014-06-01 до 2014-06-27
  4. 2014-06-28 до 2014-10-19

Я попытался использовать функцию для проверки перекрытий как таковых:

!($lhs['RecordOnset'] > $rhs['RecordOffset'] || $lhs['RecordOffset'] < $rhs['RecordOnset'])

И использовал цикл for для проверки наложения:

for($i = 1; $i < sizeof($arr1); $i++) {
for($j = 1; $j < sizeof($arr2); $j++) {
$record = $arr1[$i];
if($result = $this->intersects($arr1[$i], $arr2[$j])) {
// $result;
}
}
}

Проблема, с которой я сталкиваюсь, заключается в том, что, когда я разбиваю диапазон дат, он не проверяет новый диапазон, созданный при цикле. У меня нет возможности использовать SQL с этим, поэтому я должен придумать программное решение. Я пробовал несколько разных методов, включая некоторые циклы foreach.

Данные принимаются в формате даты, как показано в массиве, например:

$arr1 = array(array('start'=>'04/05/2014', 'end'=> '2014-06-27'), array('start'=>'2014-06-28', 'end'=> '2014-10-19'));

$arr2 = array(array('start'=>'04/05/2014', 'end'=> '2014-05-02'), array('start'=>'2014-05-03', 'end'=> '2014-05-31'),array('start'=>'2014-06-01', 'end'=> '2014-10-19'));

Вторая пара будет отдельным массивом, поскольку она может иметь одинаковые ключи.

Любое руководство или помощь в этом с благодарностью. Диапазон дат с PHP имеет очень ограниченный ресурс онлайн.

3

Решение

Подготовка

$arr1 = array(
array('start'=>'2014-04-05', 'end'=> '2014-06-27'),
array('start'=>'2014-06-28', 'end'=> '2014-10-19'),
);

$arr2 = array(
array('start'=>'2014-04-05', 'end'=> '2014-05-02'),
array('start'=>'2014-05-03', 'end'=> '2014-05-31'),
array('start'=>'2014-06-01', 'end'=> '2014-10-21')
);

// merge arrays
$all = array_merge($arr1,$arr2);

// divide start-dates and end-dates into two arrays
$starts = array();
$ends = array();
foreach($all as $date){
$starts[] = $date['start'];
$ends[] = $date['end'];
}

// Remove duplicates and "sort ASC"$starts = array_unique($starts);
natsort($starts);

$ends = array_unique($ends);
natsort($ends);

echo '<pre>';
var_dump($starts,$ends);
echo '</pre>';

выход

array(4) {
[0]=>
string(10) "2014-04-05"[3]=>
string(10) "2014-05-03"[4]=>
string(10) "2014-06-01"[1]=>
string(10) "2014-06-28"}
array(5) {
[2]=>
string(10) "2014-05-02"[3]=>
string(10) "2014-05-31"[0]=>
string(10) "2014-06-27"[1]=>
string(10) "2014-10-19"[4]=>
string(10) "2014-10-21"}

Хорошо. Теперь нам нужен цикл цикла $starts: для каждого start найти ближайший end что больше чем start, Сделай это:

$ranges = array();

foreach($starts as $start){
$start_time = strtotime($start);

foreach($ends as $end){
$end_time = strtotime($end);
if ($start_time>$end_time) continue;
else{
$ranges[$end] = $start;
break;
}
}
}

// "combine"$result = array();
foreach($ranges as $end=>$start) {
$result[] = array('start' => $start, 'end' => $end);
}

// print final result
foreach($result as $item){
echo $item['start'].'  To  '.$item['end'].'<br/>';
}

выход:

2014-04-05 To 2014-05-02
2014-05-03 To 2014-05-31
2014-06-01 To 2014-06-27
2014-06-28 To 2014-10-19

Что вам нужно.

Заметка
Об этой строке в циклах:

 $ranges[$end] = $start;

У нас может быть такая ситуация:

2014-04-03 To 2014-05-02
2014-04-04 To 2014-05-02
2014-04-05 To 2014-05-02

Но это неправильно. Нужен только последний диапазон 2014-04-05 To 2014-05-02, И строка:

 $ranges[$end] = $start;

переопределить значение с тем же ключом => наконец будет установлено правильно 2014-04-05 чтобы ключ 2014-05-02,

1

Другие решения

Вот мое решение:

<?php
$array1 = array(
array('s'=>'2014-04-05','e'=>'2014-06-27'),
array('s'=>'2014-06-28','e'=>'2014-10-19')
);
$array2 = array(
array('s'=>'2014-04-05','e'=>'2014-05-02'),
array('s'=>'2014-05-03','e'=>'2014-05-31'),
array('s'=>'2014-06-01','e'=>'2014-10-19')
);

//merge arrays together
$merged_array = array_merge($array1,$array2);

//filter out duplicate start dates
$filtered_array = array();
foreach($merged_array as $k=>$v){
if(!isset($filtered_array[ $v['s'] ] )){
$filtered_array[ $v['s'] ] = $v;
}

//if the end date is before the currently saved end date (for this start date) then use it
if( strtotime($v['e']) < strtotime($filtered_array[ $v['s'] ]['e']) ){
$filtered_array[ $v['s'] ] = $v;
}
}

//reset the array to zero based
$filtered_array = array_values($filtered_array);

//sort the array by start date
$tmp = array();
foreach($filtered_array as $k=>$v){
$tmp[$k] = $v['s'];
}

array_multisort($tmp,SORT_ASC,$filtered_array);

//end date overlap checking
foreach($filtered_array as $k=>$v){
//if the end date is after (or equal to) the "next" start date, then make that end date the "yesterday" of the next start date
if( isset($filtered_array[$k+1]['s']) && strtotime($v['e']) >= strtotime($filtered_array[$k+1]['s'])  ){
$yesterday = strtotime($filtered_array[$k+1]['s']) - 1;
$yesterday = date("Y-m-d",$yesterday);
$filtered_array[$k]['e'] = $yesterday;
}
}

echo '<pre>',print_r($filtered_array),'</pre>';

/*
Array
(
[0] => Array
(
[s] => 2014-04-05
[e] => 2014-05-02
)

[1] => Array
(
[s] => 2014-05-03
[e] => 2014-05-31
)

[2] => Array
(
[s] => 2014-06-01
[e] => 2014-06-27
)

[3] => Array
(
[s] => 2014-06-28
[e] => 2014-10-19
)

)
*/
1

По вопросам рекламы [email protected]