PHP显示短月的数组作为范围

时间:2018-01-31 15:15:53

标签: php date

我需要显示一系列短月日期作为范围。即如果有连续月份的数组,则输出最低和最高月份,并将文本"放在"他们之间。

e.g。阵列' 2月,3月,4月,5月,6月,7月,8月,9月,10月'

输出为' 2月到10月'

如果连续几个月有多组,请为每组进行以上操作

e.g。阵列' 2月,3月,4月,5月,8月,9月,10月'

输出为' 2月至5月,8月至10月'

到目前为止,我已经使用了以下代码但输出在某些月份丢失了。即下面的代码输出' 3月,5月,8月,10月'

$seasons_raw = 'Feb, Mar, Apr, May, Aug, Sep, Oct';
$seasons_arr = explode(",",$seasons_raw);
$seasons_numeric = array();
$seasons_ranges = array();
$group_id = 0;
$last = false;
foreach($seasons_arr as $season_raw){
    $month = (int)date('m', strtotime($season_raw));
    if($month - $last > 1){
        $group_id++;
    }   
    $seasons_numeric[$group_id][] = $month;
    $last = $month;
}

foreach($seasons_numeric as $season_section){
    $first_obj   = DateTime::createFromFormat('!m', $season_section[0]);
    $last_obj   = DateTime::createFromFormat('!m', $season_section[count($season_section)-1]);
    if($first_obj == $last_obj){
        $seasons_ranges[] = $first_obj->format('M');
    }
    else{
        $seasons_ranges[] = $first_obj->format('M') . ' to ' . $last_obj->format('M');
    }
}
$seasons = implode(', ',$seasons_ranges);
echo $seasons;

由于

4 个答案:

答案 0 :(得分:1)

<?php

$input = 'Jan, Feb, Mar, May, Jun, Jul, Aug, Sep, Oct, Dec';

$month_number = array_flip(['Jan','Feb','Mar','Apr','May','Jun','Jul', 'Aug','Sep','Oct','Nov','Dec']);

$input = array_map(function($m) { return trim($m); }, explode(',',$input));

$groups = [];

while ( $current = current($input) ) {
    $start = $current;
    $i = 0;
    do {
        $next = next($input);
        $i++;
    } while ( $next && $month_number[$next] == $month_number[$current] + $i );
    $stop = $next ? prev($input) : end($input);
    $groups[] = [$start, $stop];
    next($input);
}

echo implode(', ', array_map(function($group) {
    return $group[0] == $group[1] ? $group[0] : sprintf('%s to %s', $group[0], $group[1]);
}, $groups));

这将输出:

  

1月至3月,5月至10月,12月

答案 1 :(得分:1)

这不起作用。

$month = (int)date('m', strtotime($season_raw));

替换为自定义功能:

<?php

function debugout($msg) {
    echo "DEBUG: " . $msg . "\n";
}
function monthToNum($monthString) {
    $m = ['Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5, 'Jun' => 6, 
    'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12];
    return $m[trim($monthString)] ?? null;
}
$seasons_raw = 'Feb, Mar, Apr, May, Aug, Sep, Oct';
$seasons_arr = explode(",",$seasons_raw);
$seasons_numeric = array();
$seasons_ranges = array();
$group_id = 0;
$last = false;
foreach($seasons_arr as $season_raw){

    // $month = (int)date('m', strtotime($season_raw));
    $month = monthToNum($season_raw);
    if ( empty($month) ) {
        // Check just in case
        throw new Exception("Bad month string {$season_raw}");
    }
    debugout("month  '{$season_raw}' -> '{$month}'");

    if($month - $last > 1){
        $group_id++;
    }   
    $seasons_numeric[$group_id][] = $month;
    $last = $month;
}

foreach($seasons_numeric as $season_section){
    $first_obj   = DateTime::createFromFormat('!m', $season_section[0]);
    $last_obj   = DateTime::createFromFormat('!m', $season_section[count($season_section)-1]);
    if($first_obj == $last_obj){
        $seasons_ranges[] = $first_obj->format('M');
    }
    else{
        $seasons_ranges[] = $first_obj->format('M') . ' to ' . $last_obj->format('M');
    }
}
$seasons = implode(', ',$seasons_ranges);
echo $seasons;

答案 2 :(得分:1)

只要没有使用多个非连续范围,下面的代码或多或少都会实现目标,可能不会像目前那样精确。在给定输入数据的情况下,我认为不需要实际使用任何dateDateTime函数,因此这只适用于数组。

function makerange( $str=false ){
    if( $str ){

        $tmp=$out=array();
        $linear=true;

        $year = explode( ',', 'Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec' );
        $months = explode( ',', $str );

        array_walk( $year, function( &$item ){ $item=trim( $item );});
        array_walk( $months, function( &$item ){ $item=trim( $item );});

        foreach( $months as $month ){
            $tmp[]=array_search( $month, $year );
        }


        foreach( $tmp as $key => $month ){
            if( $key > 0 && $key < count( $tmp ) - 1 ) {
                if( $tmp[ $key + 1 ] - $month > 1 ){
                    $linear=false; break;
                }
            }
        }

        if( !empty( $tmp ) ){

            $out[]=$year[ $tmp[0] ];

            if( !$linear ){
                $out[]=$year[ $tmp[ $key ] ];
                $out[]=$year[ $tmp[ $key + 1 ] ];
            }
            $out[]=$year[ $tmp[ count( $tmp ) - 1 ] ];



            $bits=array_chunk( $out, 2 );

            if( !$linear ){
                $from=implode( '-', $bits[ 0 ] );
                $to=implode( '-', $bits[ 1 ] );

                return sprintf('From: %s To: %s', $from, $to );
            } else {
                $from = implode( '-', $bits[ 0 ] );

                return sprintf('Linear range: %s ', $from );
            }
        }
        return false;
    }
}


$str='Feb, Mar, Apr, May, Jun, Aug, Sep, Oct';
printf('%s<br/>%s<br/><br/>', $str, makerange( $str ) );

$str='Jan, Feb, Mar, May, Jun, Jul, Aug, Sep, Oct';
printf('%s<br/>%s<br/><br/>', $str, makerange( $str ) );

以上将输出

Feb, Mar, Apr, May, Jun, Aug, Sep, Oct
From: Feb-Jun To: Aug-Oct

Jan, Feb, Mar, May, Jun, Jul, Aug, Sep, Oct
From: Jan-Mar To: May-Oct

答案 3 :(得分:-2)

编写一个如下所示的简单函数,然后在任意位置调用它。

function ShowMonths($start, $finish = 12)
{
  # lets seed month 0 with a NULL so the months can be 1-12
  $month[] = NULL;
  for ($i=1;$i<13;$i++) {
      $month[] = date('M', strtotime('01.'.$i.'.2000'));
  }
    if ($start < 0 || $start > 11) {
        die("Start month incorrect");
    }
    if ($finish < 1 || $finish > 12) {
        die("Finish wrong");
    }
    if ($start >= $finish) {
        die("Finish larger than start");
    }
    print $month[$start] . " to " . $month[$finish];
}

ShowMonths(1, 2);