datetime: разделить месяц на 10-дневные периоды

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

Пример с 14.01.2016

Мне нужно, чтобы результат был точно таким, как показано ниже:

  • С 11 января 2016 года по 20 января 2016 года
  • С 21 января 2016 года по 31 января 2016 года
  • С 1 февраля 2016 по 10 февраля 2016
  • С 11 февраля 2016 года по 20 февраля 2016 года
  • С 21 февраля 2016 по 29 февраля 2016
  • С 1 марта 2016 года по 10 марта 2016 года
  • С 11 марта 2016 года по 20 марта 2016 года
  • С 21 марта 2016 года по 31 марта 2016 года
  • С 1 апреля 2016 по 10 апреля 2016
  • С 11 апреля 2016 года по 20 апреля 2016 года

Вот мой код:

function date_interval($startTime = false){

if( ! $startTime){

return array();
} else {

if(date('d',$startTime) < 10){
$actual = mktime(0, 0, 0, date('m',$startTime), 1, date('Y',$startTime));
} elseif(date('d',$startTime) < 20){
$actual = mktime(0, 0, 0, date('m',$startTime), 10, date('Y',$startTime));
} else {
$actual = mktime(0, 0, 0, date('m',$startTime), 20, date('Y',$startTime));
}

if(date('d',time()) < 10) {
$target = mktime(0, 0, 0, date('m',time()), 10, date('Y',time()));
} elseif(date('d',time()) < 20) {
$target = mktime(0, 0, 0, date('m',time()), 20, date('Y',time()));
} else {
$target = mktime(0, 0, 0, date('m',time())+1, 1, date('Y',time()));
}$current = $actual;
$last = $actual;

while($current < $target) {

if(date('d',$current) < 10){
$current = mktime(0, 0, 0, date('m',$current), 10, date('Y',$current));
} elseif(date('d',$current) < 20){
$current = mktime(0, 0, 0, date('m',$current), 20, date('Y',$current));
} else {
$current = mktime(0, 0, 0, date('m',$current)+1, 1, date('Y',$current));
}
$dateTime[date("Y-m-d", $last) .'~'. date("Y-m-d", $current)] = date('d M Y',$last) . ' - ' . date('d M Y',$current));
$last = $current;
}
}
return $dateTime;
}

0

Решение

Datetime — это дорогой класс из php, который хорошо решает эту проблему.
Здесь вы передаете начальную дату функции как объект DATETIME, и функция отбрасывает стек тегов списка.

В цикле startDay изменяется сначала, добавляя 10 дней, чтобы совершить прыжок, а затем на один, чтобы избежать перекрытия.
Если вы хотите получить последнюю строку с периодом времени (менее десяти дней) с последнего дня начала до сегодняшнего дня, вы можете добавить что-то вроде:

$return .= '<li>From '.$startDay->format('d M Y').' to '.$today->format('d M Y').'</li>';

после цикла

function date_interval(DATETIME $startDay = NULL)
{
if( NULL == $startDay){
return array(); }

$return = '';
$today = new DATETIME('now');

while(  $today->diff( $startDay )->format('%a%') > 10  )
{
$return .= '<li>From '.$startDay->format('d M Y').' to ';
$startDay->modify('+10 days');
$return .= $startDay->format('d M Y').'</li>
';
$startDay->modify('+1 day');
}
return $return;
}

Я изменил приведенное выше более общее решение, чтобы сделать именно то, что вы описываете:

    <?php
function date_interval(DATETIME $startDay = NULL)
{
if( NULL == $startDay){
return array(); }

$return = '';
$today = new DATETIME('now');
$startMonth = new DateTime('first day of '.$startDay->format('M Y') );
$firstRun = TRUE;

while(  $today > $startDay )
{
$return .= '<li>From '.$startDay->format('d M Y').' to ';
if( $firstRun == TRUE ){
if( (int)$startDay->format('d') > 10 )
$startMonth->modify('+10 days');
if( (int)$startDay->format('d') > 20 )
$startMonth->modify('+10 days');
$startDay = $startMonth;

$firstRun = FALSE;
}
$lastOfMonth = new DateTime('last day of '.$startDay->format('M Y') );
if( $lastOfMonth->diff( $startDay )->format('%a%') > 10 )
$startDay->modify('+9 days');
else
$startDay = $lastOfMonth;

$return .= $startDay->format('d M Y').'</li>
';
$startDay->modify('+1 day');
}
return $return;
}

echo date_interval( date_create_from_format('Y-m-d','2016-01-21') )."\n";

?>
1

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

Смотрите эту функцию, используя DateTime:

function date_interval( $start = Null )
{
if( !$start ) return array();

$cur    = new DateTime( sprintf( '%s-%02d', $start->format('Y-m'), [1,11,21,21][ floor(($start->format('j')-1)/10) ] ) );
$end    = new DateTime();
$retval = [];

while( $cur <= $end )
{
$key = $cur->format( 'Y-m-d~' );
$val = $cur->format( 'd M Y - ' );
if( $cur->format( 'j' ) > 20 ) $cur->modify( 'last day of this month' );
else                           $cur->modify( '+ 9 days' );
$retval[ $key.$cur->format( 'Y-m-d' ) ] = $val.$cur->format( 'd M Y' );
$cur->modify( '+ 1 days' );
}
return $retval;
}

Называя это таким образом:

$startDate = '14/01/2016';
$array = date_interval( DateTime::createFromFormat( 'd/m/Y', $startDate ) );
print_r( $array );

В соответствии с вашей схемой ключей / значений, результирующий массив:

Array
(
[2016-01-11~2016-01-20] => 11 Jan 2016 - 20 Jan 2016
[2016-01-21~2016-01-31] => 21 Jan 2016 - 31 Jan 2016
[2016-02-01~2016-02-10] => 01 Feb 2016 - 10 Feb 2016
[2016-02-11~2016-02-20] => 11 Feb 2016 - 20 Feb 2016
[2016-02-21~2016-02-29] => 21 Feb 2016 - 29 Feb 2016
[2016-03-01~2016-03-10] => 01 Mar 2016 - 10 Mar 2016
[2016-03-11~2016-03-20] => 11 Mar 2016 - 20 Mar 2016
[2016-03-21~2016-03-31] => 21 Mar 2016 - 31 Mar 2016
[2016-04-01~2016-04-10] => 01 Apr 2016 - 10 Apr 2016
[2016-04-11~2016-04-20] => 11 Apr 2016 - 20 Apr 2016
[2016-04-21~2016-04-30] => 21 Apr 2016 - 30 Apr 2016
)

Мы работаем только на одну дату ($cur), изначально созданный из переданного аргумента; мы устанавливаем день месяца, используя массив [1,11,21,21] и выберите ключ с округленным делением на 10 от исходного дня (в вашем примере (14-1) / 10 = 1,3, округленное до 1, то есть 11 в [1,11,21,21] массив). Это быстрый способ решить 31 день исключение.

Затем мы выполняем цикл до $cur дата больше, чем сегодняшняя дата: мы создаем начальную часть ключа и значения, мы модифицируем $cur добавив его девять дней или выбрав день прошлого месяца, мы создадим полный ключ и значение возвращаемого массива. В конце каждого цикла мы увеличиваем $cur на 1 день.

0

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