Повторение событий в" 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");
}
}
}