创建例外日期范围

时间:2015-01-15 12:23:15

标签: php date range

有两个日期数组(mm / dd / yyyy)

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);

3 个答案:

答案 0 :(得分:1)

有趣的挑战:)!所以我试了一下:

$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);

答案 1 :(得分:1)

好的,这与你所获得的并没有太大的不同,但它是另一种观点,我使用的是strtotime()函数,而不是mktime()至少看起来更好。

我假设输入已经过验证,并且我忽略了角落情况,例如当所需范围/周期的开始日期在第一个“无用的”范围内时。范围,或结束日期是无用的&#39;范围,但如果有必要,这可以很容易地验证。

我只是想让你分享我将如何解决这个问题。

这是我的代码:

<?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 />';
    }

答案 2 :(得分:1)

假设您只需要生成一个字符串,并且日期已经过验证并按顺序排列,我就不会为日期函数烦恼了。以下是我将如何做的一个简单示例:

$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

说明:

一般的想法是建立一个句子,所以我不打扰日期或范围或任何东西。想象一下需要拼凑在一起的单词。最终结果必须是:

  

&#34; range0 useless_range0 useless_range1 useless_range2 useless_range3 range1 &#34;

这可以这样分解:

  

[ range0 ]到[ useless_range0 useless_range1 ]到[ useless_range2 useless_range3 ]到[ range1 ]

使用&#34;内爆可以很容易地实现这一点。到&#34;作为分隔符。我们只需要生成数组,其中 range0 作为第一个元素, range1 作为最后一个元素,以及每一句话(两个连续日期+&#34;和&#34) ;)之间。这是一个简单的循环+ array_shift / unshift。

注意:如果您的日期未经过验证,或者您需要检查重叠或任何类似的东西,那么您很可能必须像您一样构建一系列日期。