Повторение событий в" N-й " будний день каждого месяца

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

у меня есть ежедневные, еженедельные, ежемесячные и ежегодные повторы, которые сейчас работают нормально (мне все еще нужно обновить систему с исключительными событиями и тому подобным, но пока это работает). Но, мы хотим иметь возможность добавлять возможность повторять события на (1-й,2-й,3-й, 4-й,5-й) [Sun / Mon|Tue|Wed|Thu|Fri / Sat] каждого месяца, каждого второго месяца и каждые три месяца.

теперь, если я могу просто понять логику для каждого месяца, я могу вычислить каждые два месяца и каждые три месяца.

вот немного из того, что я до сих пор (примечание: Я не говорю, что есть лучший способ сделать это, или ничего, но система одна мы обновляем постепенно, со временем, когда мы не заняты другими проектами, так что мне сделать код более эффективным, как у меня время.)

сначала я получаю начальную и конечную даты в формате даты расчетов:

$ending = $_POST['end_month'] . "/" . $_POST['end_day'] . "/" . substr($_POST['end_year'], 2, 2);
$starting = $_POST['month'] . "/" . $_POST['day'] . "/" . substr($_POST['year'], 2, 2);

затем я получаю разницу между этими двумя, чтобы узнать, сколько раз повторять с помощью функции, которую я довольно уверен, что нашел здесь некоторое время назад, и деление этой суммы на 28 дней, чтобы получить примерно сколько раз нужно повторить, чтобы был один в месяц:

$repeat_number = date_diff($starting, $ending) / 28;
//find the difference in DAYS between the two dates
function date_diff($old_date, $new_date) {
$offset = strtotime($new_date) - strtotime($old_date);
return $offset/60/60/24;
}

затем я добавляю (1-й, 2-й и т. д...) часть к [Sun / Mon / etc... часть, чтобы выяснить, что они ищут, чтобы дать мне что-то вроде "первого воскресенья":

$find = $_POST['custom_number']. ' ' . $_POST['custom_day'];

затем я использую цикл, который запускает количество раз, которое нужно повторить ($repeat_number сверху):

for($m = 0; $m <= $repeat_number; $m++) {
if($m == 0) {
     $month = date('F', substr($starting,0,2));
} else {
     $month = date('F', strtotime($month . ' + ' . $m . ' months'));
}
$repeat_date = strtotime($find . ' in ' . $month);
}

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

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

заранее спасибо за любой вход или советы вы можете предоставить.

3 ответов


вот возможная альтернатива для вас. strtotime мощный, и синтаксис включает в себя действительно полезные биты как всеобъемлющая относительная формулировка времени и даты.

вы можете использовать его для создания первых через N-й конкретных рабочих дней определенного месяца, используя формат "of". Вот пример использования date_create вызвать DateTime объект, но обычный старый strtotime работает так же путь:

php > $d = date_create('Last Friday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Friday March 25 2011 00:00:00
php > $d = date_create('First Friday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Friday March 04 2011 00:00:00
php > $d = date_create('First Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday March 06 2011 00:00:00
php > $d = date_create('Fourth Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday March 27 2011 00:00:00
php > $d = date_create('Last Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday March 27 2011 00:00:00

он также переполнит месяц, если вы попросите недействительный:

php > $d = date_create('Ninth Sunday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d Y H:i:s');
Sunday May 01 2011 00:00:00

обратите внимание, что он работает только с порядковый номер формулировку. Вы не можете пройти "1-й" или "3-й", К сожалению.

как только вы используете это, чтобы захватить правильный N-й будний день, Вы можете просто добавить количество необходимых будних дней, чтобы пропустить (7 на одну неделю, 14 на две, 21 на три и т. д.) , Как требуется до назначенной даты окончания или назначенного количества недель прошел. Еще раз,strtotime на помощь, используя второй аргумент для связывания относительности:

php > echo date('l F d Y H:i:s', strtotime('+14 days', strtotime('First Thursday of March 2011')));
Thursday March 17 2011 00:00:00

(моя локальная копия также принято '+14 days First Thursday of March 2011', но это было довольно странно.)


У меня есть более простой метод, хотя он может показаться hack-ish.

что мы можем сделать, это взять дату начала и вывести из нее значение "n", взяв потолок его дня, разделенный на 7.

например, если ваша дата начала 18-го числа, мы делим на 7 и берем потолок, чтобы сделать вывод, что это 3-й "независимо-день" месяца.

оттуда мы можем просто повторно добавить 7 дней к этому, чтобы получить новую дату, и всякий раз, когда новая дата потолочная 7-коэффициент равен 3, мы попали в следующий "N-й день" месяца.

некоторый код можно увидеть ниже:

$day_nth = ceil(date("j", strtotime($date))/7);
for ($i = 0; $i < $number_of_repeats; $i++) {

    while (ceil(date("j", strtotime($date))/7) != $day_nth)
        $date = date("Y-m-d", strtotime("+7 days", strtotime($date)));

    /* Add your event, or whatever */

    /* Now we increment date by 7 days before the loop starts again,
    ** otherwise the while loop would never execute and we'd just be
    ** adding to the same date repeatedly. */
    $date = date("Y-m-d", strtotime("+7 days", strtotime($date)));
}

Я делаю это так:

            //$typeOfDate = 0;
            $typeOfDate = 1;
            $day = strtotime("2013-02-01");
            $to = strtotime(date("Y-m-d", $day) . " +6 month");

            if ($typeOfDate == 0) { //use the same day (number) of the month
                $dateArray[] = date("Y-m-d", $day);
                $event_day_number = date("d", $day);
                while ($day <= $to) {
                    $nextMonth = date("m", get_x_months_to_the_future($day));
                    $day = strtotime(date("Y-" . $nextMonth . "-d", $day));
                    $dateArray[] = date("Y-m-d", $day);
                }
            }

            if ($typeOfDate == 0) { //use the same day (like friday) of the month
                $dateArray[] = date("Y-m-d", $day);
                $monthEvent = date("m", $day);
                $day = strtotime(date("Y-m-d", $day) . " +4 weeks");
                $newMonthEvent = date("m", $day);
                if ($monthEvent == $newMonthEvent) {
                    $day = strtotime(date("Y-m-d", $day) . " +7 days");
                }
                while ($day <= $to) {
                    $dateArray[] = date("Y-m-d", $day);
                    $monthEvent = date("m", $day);
                    $day = strtotime(date("Y-m-d", $day) . " +4 weeks");
                    $newMonthEvent = date("m", $day);
                    if ($monthEvent == $newMonthEvent) {
                        $day = strtotime(date("Y-m-d", $day) . " +7 days");
                    }
                }
            }