@alexandrtumaykin
PHP-программист

PHP. Есть ли решение, которое будет разбивать интервал дат на недельные периоды?

нужно придумать алгоритм, который будет разбивать интервал дат на недельные периоды. Неделей считается интервал от пн по вс либо текущего дня по вс (например, если первое число месяца выпадает на отличный от пн день) либо пн по текущий день (если конец месяца выпадает на день отличный от вс).

Пример:

входные данные 01.08.2014 - 30.08.2015

на выходе:

01.08.2014 - 03.08.2014

04.08.2014 - 10.08.2014

11.08.2014 - 17.08.2014

18.08.2014 - 24.08.2014

25.08.2014 - 31.08.2014

01.09.2014 - 07.09.2014

...

29.09.2014 - 30.09.2014

01.10.2014 - 05.10.2014

06.10.2014 - 12.10.2014

...
  • Вопрос задан
  • 2751 просмотр
Решения вопроса 1
@alexandrtumaykin Автор вопроса
PHP-программист
Всем спасибо. Вот мое решение:

/**
 * @param string $from начало периода
 * @param string $to   конец периода
 *
 * @return array
 */
function getWeekPeriod($from, $to)
{
    $weeks = [];
    $from = strtotime($from);
    $to = strtotime($to);

    while ($from < $to) {
//            echo "from:\t", date('d.m.Y', $from), RN;

        // номер дня недели начала периода
        $fromDay = date("N", $from);
//            echo "fromDay:\t", $fromDay, RN;

        // если не ВС
        if ($fromDay < 7) {
            // кол-во дней до ВС
            $daysToSun = 7 - $fromDay;

//                echo "daysToSun:\t", $daysToSun, RN;

            // конец недельного периода
            $end = strtotime("+ $daysToSun day", $from);

            // если попадаем на след. месяц, то делаем новые вычисления
            if (date("n", $from) != date("n", $end)) {
                $end = strtotime("last day of this month", $from);
            }

            $weeks[] = [date('d.m.Y', $from), date('d.m.Y', $end)];
            $from = $end;
        } else {
            $weeks[] = [date('d.m.Y', $from), date('d.m.Y', $from)];
        }

//            echo "end:\t", date('d.m.Y', $from), RN, RN;

        $from = strtotime("+1 day", $from);
    }

    return $weeks;
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 4
orlov0562
@orlov0562 Куратор тега PHP
I'm cool!
$start = new DateTime('01.08.2014');
$end = new DateTime('30.08.2015 23:59');
$interval = new DateInterval('P1D');
$dateRange = new DatePeriod($start, $interval, $end);

$weekNumber = 1;
$weeks = array();
foreach ($dateRange as $date) {
	$weeks[$weekNumber][] = $date->format('Y-m-d');
	if ($date->format('w') == 0) {
		$weekNumber++;
	}
}

echo '<pre>';
print_r($weeks);
echo '</pre>';
Ответ написан
Комментировать
sHinE
@sHinE
веб-разработчик, php/js/mysql и сопутствующее
Не то, чтобы прям готовое решение, но есть библиотека Carbon для работы с датами, там есть методы для определения конца недели и добавления недели а дальше вроде тривиально - нашли первый выходной и от него прибавляйте недели, пока весь период не исчерпаете.
Ответ написан
Комментировать
Akdmeh
@Akdmeh
PHP, Yii2, Music
1) функция mktime - возвращает unix timestamp для заданной даты (ну или, как вариант, функция strtotime)
2) передаем результат одной из двух выше названных функций в date('N', strtotime('01.08.2014'));
Результатом является цифра от 1 до 7, где 1 - понедельник, 7 - воскресенье. Как вариант, можно date('w'), где 0 - воскресенье, 6 - суббота.
3) и дальше реализуем как-то через цикл или еще каким-то способом.
Ответ написан
@VlasTeLiNandCPONK
Мне нужно было сделать то же самое, но диапазоны по две недели. Чтобы было по одной неделе, то надо просто убрать addWeek(). Сделал на Carbon вот так:
function getWeekPeriods(Carbon $from, Carbon $to)
    {
        $weeks = [];
        $currentDate = $from;

        while ($to->greaterThan($currentDate)) {
            $currentDate = $currentDate->startOfDay();
            $endOfTwoWeeksRange = (clone $currentDate)->addWeek()->endOfWeek();
            if ($endOfTwoWeeksRange->greaterThan($to)) {
                $weeks[] = ['start' => $currentDate->isoFormat('DD.MM.Y HH:mm:ss'), 'end' => $to->isoFormat('DD.MM.Y HH:mm:ss')];
                break;
            }
            $weeks[] = ['start' => $currentDate->isoFormat('DD.MM.Y HH:mm:ss'), 'end' => $endOfTwoWeeksRange->isoFormat('DD.MM.Y HH:mm:ss')];
            $currentDate = $endOfTwoWeeksRange->addDay();
        }
        return $weeks;
    }


Запрос:
{
    "date_from":"2023-01-03",
    "date_to":"2023-02-28"
}

Ответ:
[
    {
        "start": "03.01.2023 00:00:00",
        "end": "15.01.2023 23:59:59"
    },
    {
        "start": "16.01.2023 00:00:00",
        "end": "29.01.2023 23:59:59"
    },
    {
        "start": "30.01.2023 00:00:00",
        "end": "12.02.2023 23:59:59"
    },
    {
        "start": "13.02.2023 00:00:00",
        "end": "26.02.2023 23:59:59"
    },
    {
        "start": "27.02.2023 00:00:00",
        "end": "28.02.2023 10:00:00"
    }
]
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы