В следующем месяце, в тот же день в PHP

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

Предположим, что вы установили дату начала 1 мая, вы должны получить следующие события 1 июня, 1 июля и т.д. Проблема связана с датой начала 31-го (следующие могут быть 30 или 28 в зависимости от месяц).

Учитывая, что существуют месяцы с различным количеством дней (28, 30, 31) в зависимости от самого месяца и года... что было бы простым способом настроить это?

Рассмотрим следующую (и ошибочную) следующую следующую функцию:

$events = array()

function nextmonth($date) {
   return $date+(60*60*24*30);
}
$curr = $start;
while($curr < $end) {
    $events[ = $curr;
    $curr = nextmonth($curr);
}

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

Ответ 1

Update:

Это даст вам количество дней в данном месяце:

echo date('t', $timestamp);

Смотрите: date()

Старый ответ:

Я не уверен в алгоритме, о котором вы думаете, но я считаю, что это поможет вам:

echo date('d-M-y', strtotime('next month'));

Ответ 2

Это вернет правильную временную метку за 10 месяцев вперед: mktime(0,0,0,date("m")+$X,date('d'),date("Y"));

Ответ 3

Попробуйте это. reday - день для пополнения (в течение дня месяца). Если меньше, чем сегодня, он даст reday этого месяца, но не больше, чем нет. дней этого месяца. Если больше, чем сегодня, дайте reday следующего месяца такое же состояние. Я использую это для расчета "Next refill" ежемесячной точки заправки. return dd/mm/yyyy

function nextrefill($reday) {
    if (date("j") < $reday) {
        $numd = date("t");
        if ($reday > $numd) {
            return str_pad($numd, 2, "0", STR_PAD_LEFT).date("/m/Y");
        } else {
            return str_pad($reday, 2, "0", STR_PAD_LEFT).date("/m/Y");
        }
    } else {
        $nextm = date('m', strtotime('first day of next month'));
        $nextmy = date('Y', strtotime('first day of next month'));
        $numd = cal_days_in_month(CAL_GREGORIAN, $nextm, $nextmy);
        if ($reday > $numd) {
            return str_pad($numd, 2, "0", STR_PAD_LEFT)."/".$nextm."/".$nextmy;
        } else {
            return str_pad($reday, 2, "0", STR_PAD_LEFT)."/".$nextm."/".$nextmy;
        }
    }
}

для более прямого указания (Edit)

function nextmonthday($day) {
        $next_month = date('m', strtotime('first day of next month'));
        $year_of_next_month = date('Y', strtotime('first day of next month'));
        $no_of_day_in_next_month = cal_days_in_month(CAL_GREGORIAN, $nextm, $nextmy);
        if ($day > $no_of_day_in_next_month){
            return str_pad($no_of_day_in_next_month, 2, "0", STR_PAD_LEFT)."/".$next_month."/".$year_of_next_month;
        } else {
            return str_pad($day, 2, "0", STR_PAD_LEFT)."/".$next_month."/".$year_of_next_month;
        }
}

Ответ 4

Я рекомендую прочитать следующий комментарий на php.net. strtotime() (php.net)

Изменить: следующий ответ дает "резюме" ссылки, которую я разместил для тех, кто не может расшифровать содержимое, показанное там.

Ответ 5

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

Пример:

June 5, 2009, next month would be July 5, 2009
August 31, 2009, next month would be September 30, 2009

или просто, strtotime("+1 month")

Ответ 6

Пробовал это как жаворонок, и он действительно работает

strtotime('last day next month')

Итак:

$today_next_month = strtotime('this day next month');
$last_day_next_month = strtotime('last day next month');
if (date('d', $today_next_month) < date('d', $last_day_next_month)){
    $date = date('m-d-Y', $last_day_next_month); 
} else {
    $date = date('m-d-Y', $today_next_month);
}
echo "And the winner is : $date<br/>";

Ответ 7

Простой

public function adicionarMesMantendoDia($date, $months, $format = "Y-m-d"){
        $date = \DateTime::createFromFormat($format, $date);

        for($i=0;$i < $months; $i++){
            $date->modify('+ ' . date("t", $date->getTimestamp())  . ' day');
        }
        return $date;
}

Ответ 8

Как насчет этой функции:

    function getNextMonthN($date, $n = 1) {
      $newDate = strtotime('+' . $n . ' months', $date);
      if (date('j', $date) !== (date('j', $newDate))) {
        $newDate = mktime(0, 0, 0, date('n', $newDate), 0, date('Y', $newDate));
      }
      return $newDate;  
    }

На веб-сайте php.net есть другое решение под заголовком strtotime в комментарии.

Ответ 9

Никто не упомянул об этой альтернативе, хотя результат такой же, как и другие, и, вероятно, не то, что ищет OP:

$today = new DateTime();
$today->modify("+1 month");
echo $today->format("d.m.Y");

Почему бы просто не хранить месяц и день отдельно и не увеличивать месяц на один, а затем использовать функцию PHP checkdate для проверки даты, уменьшая день на один до даты?

Ответ 10

Я знаю, что это старый пост, но подумал, что он предлагает другой подход.

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

date("m", strtotime($current."+1 month"));

Затем получите день текущего месяца, используя date("d"), и сравните со следующим месяцем с приведенным выше кодом.

Ответ 11

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

$startDate = date("Y-m-d");
$month = date("m",strtotime($startDate));
$nextmonth = date("m",strtotime("$startDate +1 month"));
if((($nextmonth-$month) > 1) || ($month == 12 && $nextmonth != 1))
{
    $nextDate = date( 't.m.Y',strtotime("$startDate +1 week"));
}else
{
    $nextDate = date("Y-m-d",strtotime("$startDate +1 month"));
}
echo $nextSameDate = date("Y",$nextDate).'-'.date("m",$nextDate).'-'.date("d",$startDate);

Ответ 12

Стиль OAT для Datetime

<?php
//Start Date -> 18-09-2015
$expiry = new DateTime();
for($i=1;$i<5;$i++){
   $expiry->modify('+1 Month');
   echo $expiry->format('d-m-Y');
   echo '<br>';
}
?>

//18-10-2015
//18-11-2015
//18-12-2015
//18-01-2016

Ответ 13

Это то, что я использую

Это временная метка текущей даты месяца

$month_timestamp = strtotime(date('Y-m', $create_timestamp));

Текущий день

$current_day = date('d');

И это в следующем месяце в тот же день в формате "Y-m-d"

$next_month_first = date('Y-m-' . $current_day, strtotime('next month', $month_timestamp));

Ответ 14

Ни одно из вышеперечисленных не заботилось о не существующих днях (например, 30 февраля или 31 апреля), поэтому вот моя функция:

<?php
function getSameDayNextMonth($time, $numberMonthsToAdd = 1)
{
    list($year, $month, $day) = explode('-', date("Y-m-d", $time));

    // replace the day by one temporarily (just to make sure it exists for any month
    $numberOfYearsToAdd = floor($numberMonthsToAdd / 12);
    $year += $numberOfYearsToAdd;
    $month = ($month + $numberMonthsToAdd) % 12;
    if (0 === $month) {
        $month = 12;
    }
    $monthFormatted = sprintf('%02s', $month);
    $nbDaysInThisMonth = date("t", strtotime("$year-$monthFormatted-01"));

    if ((int)$day > $nbDaysInThisMonth) {
        $day = $nbDaysInThisMonth;
    }
    $day = sprintf('%02s', $day);
    return strtotime("$year-$monthFormatted-$day");
}


$time = strtotime("2017-10-31");
for ($i = 0; $i <= 15; $i++) {
    $_time = getSameDayNextMonth($time, $i);
    echo date("Y-m-d", $_time) . '<br>';
}

/**
 * 2017-10-31
 * 2017-11-30
 * 2017-12-31
 * 2017-01-31
 * 2017-02-28
 * 2017-03-31
 * 2017-04-30
 * 2017-05-31
 * 2017-06-30
 * 2017-07-31
 * 2017-08-31
 * 2017-09-30
 * 2018-10-31
 * 2018-11-30
 * 2018-12-31
 * 2018-01-31
 */