2016-04-05 4 views
1

Мне дается массив, содержащий периоды в течение года следующим образом.Рассчитать год из набора дат

$year = '2016'; 
$periods = [ 
     [ 
      'name' => "Name One", 
      'startDate' => '01/01/2016', 
      'endDate' => '03/31/2016' 
     ], 
     [ 
      'name' => "Name Two", 
      'startDate' => '04/01/2016', 
      'endDate' => '12/31/2016' 
     ] 
    ]; 

Число периодов может изменяться, следовательно, массив периоды может иметь любое число элементов (скажем 5 элементов, что означает 5 периодов для данного года). Теперь мне нужно убедиться, что периоды действительно составляют год, то есть два периода не могут пересекаться и периоды коллективно делают сумму до указанного года.

Я пробовал много разных способов, но не смог найти ни одного эффективного решения. Я использую Laravel 5, следовательно, Carbon package. Но я буду рад сделать это даже в Basic PHP. Поэтому все предложения приветствуются.

+0

Когда вы говорите, что вам нужно «удостовериться», что они образуют год, вы имеете в виду «проверить, составляют ли они год» или «сделать их формой года, если они этого не сделают»? –

+2

Я думаю, что начать с такого рода массива было бы полезно, в начале (по возрастанию). Затем вы можете сравнить, что следующая дата начала> предыдущая, и на один день больше, чем предыдущая дата окончания. –

+0

@hairraisin "проверить, образуют ли они год" –

ответ

2

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

Я предположил, что ваш массив $periods будет в порядке даты. Если это не так, вы можете просто usort.

$year = '2016'; 
$periods = [ 
    [ 
     'name' => "Name One", 
     'startDate' => '01/01/2016', 
     'endDate' => '03/31/2016' 
    ], 
    [ 
     'name' => "Name Two", 
     'startDate' => '04/01/2016', 
     'endDate' => '12/31/2016' 
    ] 
]; 

// set a start position 
$currentPosition = Carbon::create($year, 1, 1)->startOfDay(); 
// and the end of the year 
$endOfYear = Carbon::create($year, 1, 1)->addYear()->startOfDay(); 

// iterate periods 
foreach ($periods as $period) { 
    $start = Carbon::createFromFormat('m/d/Y', $period['startDate'])->startOfDay(); 
    $end = Carbon::createFromFormat('m/d/Y', $period['endDate'])->endOfDay(); 

    // start of this period should follow the last (??) 
    if ($start < $currentPosition) { 
     throw new Exception("$start is earlier than $currentPosition"); 
    } 

    // must follow on from the current position 
    if ($currentPosition->diffInDays($start) > 0) { 
     throw new Exception("$start doesn't follow $currentPosition"); 
    } 

    // check it doesn't go over the end of the year 
    if ($currentPosition->addDays($start->diffInDays($end)) > $endOfYear) { 
     throw new Exception("$end takes us over the end of the year!"); 
    } 

    $currentPosition = clone $end; 
} 

// did we reach the end? 
if ($currentPosition->addDay()->startOfDay() != $endOfYear) { 
    throw new Exception("Full year not accounted for"); 
} 

// we're done 
echo 'Full year accounted for'.PHP_EOL;