可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an "event" that needs to be scheduled the same day of every month.
Say you set the start date on the 1st May you should get the next events on the 1st of Jun, 1 Jul etc. The problem comes with a start date on the 31st (the next ones could be 30 or 28 depending on the month).
Considering that there are months with different numbers of days (28, 30, 31) depending on the month itself and the year... what would be an easy way to setup this?
Consider the following (and flawed) nextmonth function:
$events = array() function nextmonth($date) { return $date+(60*60*24*30); } $curr = $start; while($curr < $end) { $events[ = $curr; $curr = nextmonth($curr); }
Edited to add: The problem for me is, simply enough, how to solve what the number of days of any given month is and thus get the next corresponding date.
回答1:
Update:
This will give you the number of days in given month:
echo date('t', $timestamp);
See: date()
Old answer:
I'm not sure about the algorithm you're thinking of but I believe this will help you:
echo date('d-M-y', strtotime('next month'));
回答2:
This will return proper timestamp for $X months ahead: mktime(0,0,0,date("m")+$X,date('d'),date("Y"));
回答3:
Try this. reday is day to refill(int - day of month). If less than today, it will give reday of this month but not much than no. of this month days. If more than today give reday of next month same condition. I use this for calculate "Next refill" of monthly refill point. return is 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; } } }
for more direct to point (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:
I recommend reading the following comment on php.net. strtotime() (php.net)
Edit: The next answer gives the "summary" of the link I posted for those not able to decipher the content shown there.
回答5:
Since months are so varied in size, wouldn't the best way to set the next month be something like: this day, next month except if this day doesn't exist next month.
Example:
June 5, 2009, next month would be July 5, 2009 August 31, 2009, next month would be September 30, 2009
or simply, strtotime("+1 month")
回答6:
Tried this as a lark, and it actually works
strtotime('last day next month')
So :
$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:
Simple
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:
None of the above took care of non existing days (30 february, or 31 april for instance), so here is my function:
<?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 */
回答9:
How about this function:
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; }
There is another solution on the php.net manual site under the strtotime entry in the comments.
回答10:
No one's mentioned this alternative, though the result is the same as the others, and probably not what the OP is looking for:
$today = new DateTime(); $today->modify("+1 month"); echo $today->format("d.m.Y");
Why not then just store month and day separately and increment month by one, and then use PHP's checkdate function to validate the date, decreasing the day by one until the date is valid?
回答11:
I know this is an old post but thought to give a different approach.
So instead of trying to figure out the days in a month (which is somewhat complicated), one can find out the next month using the current month easily, e.g.:
date("m", strtotime($current."+1 month"));
Then get the day of the current month using date("d"), and concat with the next month from the code above.
回答12:
I also had same problem but when i tried above solutions they could not work perfectly for me, I tried on my end and came up with new solution which is:
$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);
回答13:
Datetime OOP Style
<?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
回答14:
A lot of time passed but in case someone is searching for this, Among all the answers above I found that only @ling answer actually answer this question, but still his answer was not 100% accurate, it output the year part incorrectly as you can see in his result above.
Here is modified version of his code that fix the year problem ( I also modified it to use DateTime class instead)
/** * Adding month in PHP using DateTime * class will render the date in a way that * we do not desire, for example adding one month * to 2018-01-31 will result in 2018-03-03 but * we want it to be 2018-02-28 instead. * * This method ensure that adding months * to a date get caculated properly. * * * @param DateTime $startDate * @param int $numberOfMonthsToAdd * * @return DateTime */ function getSameDayNextMonth(DateTime $startDate, $numberOfMonthsToAdd = 1) { $startDateDay = (int) $startDate->format('j'); $startDateMonth = (int) $startDate->format('n'); $startDateYear = (int) $startDate->format('Y'); $numberOfYearsToAdd = floor(($startDateMonth + $numberOfMonthsToAdd) / 12); if ((($startDateMonth + $numberOfMonthsToAdd) % 12) === 0) { $numberOfYearsToAdd--; } $year = $startDateYear + $numberOfYearsToAdd; $month = ($startDateMonth + $numberOfMonthsToAdd) % 12; if ($month === 0) { $month = 12; } $month = sprintf('%02s', $month); $numberOfDaysInMonth = (new DateTime("$year-$month-01"))->format('t'); $day = $startDateDay; if ($startDateDay > $numberOfDaysInMonth) { $day = $numberOfDaysInMonth; } $day = sprintf('%02s', $day); return new DateTime("$year-$month-$day"); } // Quick Test $startDate = new DateTime('2018-01-31'); for($i=0; $i <= 40; $i++) { echo getSameDayNextMonth($startDate, $i)->format('Y-m-d') . "\n"; }
The output :
2018-01-31 2018-02-28 2018-03-31 2018-04-30 2018-05-31 2018-06-30 2018-07-31 2018-08-31 2018-09-30 2018-10-31 2018-11-30 2018-12-31 2019-01-31 2019-02-28 2019-03-31 2019-04-30 2019-05-31 2019-06-30 2019-07-31 2019-08-31 2019-09-30 2019-10-31 2019-11-30 2019-12-31 2020-01-31 2020-02-29 2020-03-31 2020-04-30 2020-05-31 2020-06-30 2020-07-31 2020-08-31 2020-09-30 2020-10-31 2020-11-30 2020-12-31 2021-01-31 2021-02-28 2021-03-31 2021-04-30 2021-05-31
回答15:
I created a function called my_strtotime that will handle adding and subtracting months. it's basically a wrapper around strtotime.
It checks if adding or subtracting a month will safely get you the desired month with same day. If not then it does it safely.
When adding months, it adds 15 to get you safely into the next month, then returns the last day of the month. When subtracting months, it takes the first day of this month and subtracts 1.
note: As written this works for +1 month, or -1 month
function _my_strtotime($offset, $reference_date){ //$offset is a string such as (+1 month) if(strpos($offset, 'month') === false){ //exit if not addin/subtracing months return strtotime($offset, $reference_date); } $other_months_date = strtotime ( $offset, $reference_date ); $day_of_other_month = date( 'd', $other_months_date ); $day_of_reference_month = date('d', $reference_date ); //check if numerical day is different. If so manipulate. if($day_of_reference_month != $day_of_other_month){ if(strpos($offset, '-') === false){ // adding months return strtotime('last day of this month', strtotime('+15 days', $reference_date)); } else { // subtracing months return strtotime('-1 day', strtotime('first day of this month', $reference_date)); } } return strtotime($offset, $reference_date); } Test results:
input=2016-01-31 (+1 month) output=2016-02-29 //leap year input=2017-01-31 (+1 month) output=2017-02-28 input=2018-05-31 (+1 month) output=2018-06-30 input=2018-07-31 (-1 month) output=2018-06-30 input=2016-07-22 (-1 month) output=2016-06-22 input=2016-07-22 (+1 month) output=2016-08-22
回答16:
This is what I use
This is a timestamp of current month date
$month_timestamp = strtotime(date('Y-m', $create_timestamp));
Current day
$current_day = date('d');
And this is next month same day in format "Y-m-d"
$next_month_first = date('Y-m-' . $current_day, strtotime('next month', $month_timestamp));