Я просмотрел, по крайней мере, 2 дюжины тем об этом и пока еще не нашел хорошего ответа, поэтому я прихожу к вам, чтобы еще раз спросить о проблемах, связанных с ужасной темой повторных событий.
У меня есть ежедневные, еженедельные, ежемесячные и ежегодные повторы, разработанные на данный момент (мне все еще нужно обновить систему с помощью событий Exception и еще чего-то, но пока оно работает). Но мы хотим иметь возможность добавлять возможность повторять события на (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 дней, чтобы узнать, сколько раз TIMES нужно повторить так, чтобы есть один месяц:
$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 | и т. Д.], Чтобы выяснить, что они ищут, давая мне что-то вроде «первого воскресенья»:
$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); }
Теперь, я знаю, что этот код не работает, у меня в свое время был код, который вернул правильный месяц и год для повтора, но не обязательно найдет первый вторник или что бы это ни было, что искали ,
Если бы кто-нибудь мог указать мне в правильном направлении, это было бы очень признательно. Некоторое время я скрывался в сообществе, только недавно начал активно участвовать.
Заранее благодарим за любой вклад или совет, который вы можете предоставить.
Вот вам альтернатива. strtotime
является мощным, и синтаксис включает в себя действительно полезные биты, такие как всеобъемлющая относительная формулировка времени и даты .
Вы можете использовать его для создания первого по N конкретный будний день определенного месяца, используя формат «из». Вот пример использования date_create
для вызова объекта DateTime , но обычный старый strtotime
работает одинаково:
php > $d = date_create('Last Friday of March 2011'); if($d instanceof DateTime) echo $d->format('l F d YH: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 YH: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 YH: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 YH: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 YH: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 YH:i:s'); Sunday May 01 2011 00:00:00
Обратите внимание, что он работает только с порядковым номером . К сожалению, вы не можете пройти «1-й» или «3-й».
После того, как вы используете это, чтобы захватить соответствующий N-й день недели, вы можете просто добавить количество необходимых будних дней, чтобы пропустить (7 на одну неделю, 14 на двоих, 21 на три и т. Д.) По мере необходимости до указанной даты окончания или назначенного количества недели прошли. Еще раз, strtotime
на помощь, используя второй аргумент, чтобы объединить strtotime
:
php > echo date('l F d YH: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'
, но это было странно.)
У меня более простой метод, хотя это может показаться хакером.
То, что мы можем сделать, это взять дату начала и сделать вывод, что это «n» значение от нее, принимая потолок своего дня, деленный на 7.
Например, если ваша дата начала 18-го числа, мы делимся на 7 и берем потолок, чтобы сделать вывод, что это третий «любой день» месяца.
Оттуда мы можем просто многократно добавить к этому 7 дней, чтобы получить новую дату, и всякий раз, когда 7-фактор, связанный с потолком новой даты, равен 3, мы попали в следующий «nth any-day» месяца.
Ниже приведен код:
$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("Ymd", 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("Ymd", strtotime("+7 days", strtotime($date))); }
Что приятно в этом методе, так это то, что нам даже не нужно беспокоиться о том, с каким днем недели мы имеем дело. Мы просто делаем все с начала и до конца.
Я делаю это так:
//$typeOfDate = 0; $typeOfDate = 1; $day = strtotime("2013-02-01"); $to = strtotime(date("Ymd", $day) . " +6 month"); if ($typeOfDate == 0) { //use the same day (number) of the month $dateArray[] = date("Ymd", $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("Ymd", $day); } } if ($typeOfDate == 0) { //use the same day (like friday) of the month $dateArray[] = date("Ymd", $day); $monthEvent = date("m", $day); $day = strtotime(date("Ymd", $day) . " +4 weeks"); $newMonthEvent = date("m", $day); if ($monthEvent == $newMonthEvent) { $day = strtotime(date("Ymd", $day) . " +7 days"); } while ($day <= $to) { $dateArray[] = date("Ymd", $day); $monthEvent = date("m", $day); $day = strtotime(date("Ymd", $day) . " +4 weeks"); $newMonthEvent = date("m", $day); if ($monthEvent == $newMonthEvent) { $day = strtotime(date("Ymd", $day) . " +7 days"); } } }