Имеет два массива даты (мм / дд / гггг)
array(2) {
["useless_range"]=>
array(4) {
[0]=>
string(10) "08/15/2014"[1]=>
string(10) "08/30/2014"[2]=>
string(10) "09/10/2014"[3]=>
string(10) "09/20/2014"}
["range"]=>
array(2) {
[0]=>
string(10) "08/01/2014"[1]=>
string(10) "10/31/2014"}
}
Учтите, что массив range_useless — это праздник, забастовка или что-то в этом роде. Это уже отсортировано.
Как я могу получить полезный диапазон из заданного диапазона массива?
Для этого примера я хочу, чтобы диапазон был
'08/01/2014 to 08/14/2014 **and** 08/31/2014 to 09/09/2014 **and** 09/21/2014 to 10/31/2014'
Моим первым решением было создать массив всех дат между диапазонами, а затем создать полное циклическое выполнение строк, используя in_array, но я думаю, что, возможно, существует лучшее решение
Код, который создает все даты между всеми диапазонами
$strDateFrom = '2014/08/15';
$strDateTo = '2014/08/30';
// takes two dates formatted as YYYY-MM-DD and creates an
// inclusive array of the dates between the from and to dates.
$aryRange=array();
$iDateFrom=mktime(1,0,0,substr($strDateFrom,5,2), substr($strDateFrom,8,2),substr($strDateFrom,0,4));
$iDateTo=mktime(1,0,0,substr($strDateTo,5,2), substr($strDateTo,8,2),substr($strDateTo,0,4));
if ($iDateTo>=$iDateFrom) {
array_push($aryRange,date('Y-m-d',$iDateFrom)); // first entry
while ($iDateFrom<$iDateTo) {
$iDateFrom+=86400; // add 24 hours
array_push($aryRange,date('Y-m-d',$iDateFrom));
}
}
print_r($aryRange);
Интересный вызов :)! Итак, я попробовал кое-что:
$myDates = array(
"useless_range" => array(
"01/08/2015",
"01/15/2015",
"09/10/2015",
"09/20/2015"),
"range" => array(
"08/01/2015",
"10/31/2015")
);// results of strotime
$dateStart = 1420066800; //01/01/2015
$dateTo = 1422658800; // 31/01/2015$tab = $myDates['useless_range'];
$len = count($tab);
$result = array();
$previous = $dateStart;
for($i = 0; $i < $len; $i++){
$position = $tab[$i]; // we get the current element
$iPosition = strtotime($position); // strotime it
if($previous < $iPosition && $iPosition < $dateTo){ // if the useless date is in the range
if($i % 2 == 0){ //if start of range
$result[] = array("start" => date("Y-m-d", $previous + 3600*24), "end" => date("Y-m-d", $iPosition));
}
$previous = $iPosition;
}
else { // the date is out of range, we finish the result and leave the loop
$result[] = array("start" => date("Y-m-d", $previous), "end" => date("Y-m-d", $dateTo + 3600*24));
break; //end of search
}
}
print_r($result);
Выходной результат:
Array
(
[0] => Array
(
[start] => 2015-01-01
[end] => 2015-01-08
)
[1] => Array
(
[start] => 2015-01-15
[end] => 2015-01-31
)
)
Теперь, чтобы создать предложение:
$sentences = array();
foreach($result as $elem){
$sentences[] = $elem['start']." to ".$elem['end'];
}
echo implode(' **and** ', $sentences);
Хорошо, это не очень отличается от того, что у вас есть, но это другая точка зрения, и я использую strtotime()
функция вместо mktime()
что, по крайней мере, выглядит лучше.
Я предполагаю, что входные данные были проверены, и я проигнорировал угловые случаи, такие как, когда дата начала желаемого диапазона / периода находится внутри первого «бесполезного» диапазона, или дата окончания находится в «бесполезном» диапазоне, но это можно легко проверить при необходимости.
Я просто хотел, чтобы вы поделились, как бы я решил эту проблему.
Вот мой код:
<?php
$uselessRanges = [ "08/15/2014", "08/30/2014", "09/10/2014", "09/20/2014" ];
$range = [ "08/01/2014", "10/31/2014" ];
// Convert to timestamps for easier manipulation
$rangeTs = array_map( 'strtotime', $range );
$uselessRangesTs = array_map( 'strtotime', $uselessRanges );
// Let the first date be the start of the whole range
$finalResult = [ array_shift( $rangeTs ) ];
/**
* Assuming that the useless ranges array is of the following format:
* $useless = [ 'start_useless_range_1', 'end_useless_range_1', 'start_useless_range_2', 'end_useless_range_2', ... ]
*
* For each of the useless range entries we decide whether to take the previous or the next day based on the parity of the index
*/
for( $i = 0; $i < count( $uselessRangesTs); $i++ ){
// Whether we should take the previous or the next day
$diff = $i % 2 === 0 ? -86400 : 86400;
$finalResult[] = $uselessRangesTs[$i] + $diff;
}
// Finally add the end of the whole range
$finalResult[] = array_shift( $rangeTs );
foreach( $finalResult as $date ){
echo date('m/d/Y', $date) . '<br />';
}
Предполагая, что вам нужно только сгенерировать строку, а даты уже проверены и в порядке, я не стал бы беспокоиться о функциях даты. Вот быстрый пример того, как я бы это сделал:
$dates = array(
"useless_range" => array(
"08/15/2014",
"08/30/2014",
"09/10/2014",
"09/20/2014"),
"range" => array(
"08/01/2015",
"10/31/2015")
);
$str = array();
for ( $i = 0; $i < sizeof($dates['useless_range']); $i += 2 ) {
$str[] = sprintf('%s and %s', $dates['useless_range'][$i], $dates['useless_range'][$i+1]);
}
array_unshift($str, $dates['range'][0]);
$str[] = $dates['range'][1];
$str = implode(' to ',$str);
echo $str;
// 08/01/2015 to 08/15/2014 and 08/30/2014 to 09/10/2014 and 09/20/2014 to 10/31/2015
Пояснения:
Общая идея состоит в том, чтобы построить предложение, поэтому я не беспокоюсь о датах, диапазоне или чем-то еще. Просто представьте слова, которые нужно соединить. Окончательный результат должен быть:
«range0 в useless_range0 а также useless_range1 в useless_range2 а также useless_range3 в range1«
Это может быть разбито так:
[range0] до [useless_range0 а также useless_range1] до [useless_range2 а также useless_range3] до [range1]
Это может быть достигнуто очень легко с помощью взрыва, используя «to» в качестве разделителя. Нам просто нужно сгенерировать массив с range0 в качестве первого элемента, range1 как последний элемент, и каждый фрагмент предложения (две последовательные даты + «и») между ними. Это простой цикл + array_shift / unshift.
Примечание: если ваши даты не проверены, или если вам нужно проверить на совпадение, или что-нибудь подобное, то вам, скорее всего, придется создать массив дат, как вы делаете.