Reputation: 899
I am displaying month titles 3 month into the future as well as getting the 1st and last day of each of those months.
for($i = 1; $i < 4; $i++) { // For each month for 3 months
$monthTitle = date('F Y', strtotime('+'.$i.' month'));
$begin_date = date('Y-m-01', strtotime('+'.$i.' month')); // First day of calendar month in future.
$end_date = date('Y-m-t', strtotime('+'.$i.' month')); // Last day of calendar months in future.
};
Nov. 29, 2015 output is:
December 2015
2015-12-01
2015-12-31
January 2016
2016-01-01
2016-01-31
February 2016
2016-02-01
2016-02-29
This was working great right up until yesterday, Nov. 29, 2015 but today Nov. 30, 2015 it skips February.
Nov. 30, 2015 output is:
December 2015
2015-12-01
2015-12-31
January 2016
2016-01-01
2016-01-31
March 2016
2016-03-01
2016-03-31
I'm guessing a bug but does anybody know of a work around?
Upvotes: 3
Views: 3155
Reputation: 539
It's not a bug, and I'm surprised no answer makes any mention of this. It's what happens when we run it on a day like the 31st. It gets the next month and if that doesn't have 31 days, it just skips it.
Just see what I got when I ran your code today (31 Aug 2023):
October 2023 //Skips September because it doesn't have day 31
2023-10-01
2023-10-31
October 2023 //Ditto for November
2023-10-01
2023-10-31
December 2023
2023-12-01
2023-12-31
If you want to skip using DateInterval
and still use strtotime()
, just replace "+1 month" with "last day of +1 month".
Like so: strtotime('+'.$i.' month')
-> strtotime('last day of +' . $i . ' month')
for($i = 1; $i < 4; $i++) { // For each month for 3 months
$monthTitle = date('F Y', strtotime('last day of +' . $i . ' month'));
$begin_date = date('Y-m-01', strtotime('last day of +' . $i . ' month')); // First day of calendar month in future.
$end_date = date('Y-m-t', strtotime('last day of +' . $i . ' month')); // Last day of calendar months in future.
}
Output:
September 2023 //Works as we wanted
2023-09-01
2023-09-30
October 2023
2023-10-01
2023-10-31
November 2023 //Works as we wanted
2023-11-01
2023-11-30
There are these closed bug reports one in 2003 and another in 2008 from php.net. See also SeanDowney's explanation for "How to get previous month and year relative to today, using strtotime and date?"
However, I found that most of us agree that adding some mention of this behaviour in the function would save us the trouble. Worse cases would be when it tries to get the dreaded February on days 29-31 of any month.
A month is an ill-defined unit in the end and I'll leave you with this infamous comment by rasmus from those bug reports, "If I told you on January 30 that I would come back in exactly one month to beat the crap out of you, when would you think I would show up?"
Upvotes: 0
Reputation: 39
if last day of next month is needed then you can use this
$d = new DateTime( '2010-01-31' );
$d->modify( 'last day of next month' );
echo $d->format( 'Y-m-d' ), "\n";
Upvotes: 0
Reputation: 899
Thanks to @devlin carnate for pointing me in the right direction.
for($i = 1; $i < 4; $i++) { # for each month
$tmp = date('Y-m-15'); // Get the middle of the month to avoid PHP date bug.
$begin_date = date('Y-m-01', strtotime($tmp . '+'.$i.' month')); // First day of calendar month in future.
$end_date = date('Y-m-t', strtotime($begin_date)); // Last day of calendar months in future.
$monthTitle = date('F Y', strtotime($begin_date));
};
This seems to work very well.
Upvotes: 4
Reputation: 2556
You can use DateInterval to add one month to the current date, so you can get the first and the last day of month.
<?php
$date = new DateTime('2015-12-01');
$i = 0;
while($i < 3){
printf("%s | first day: %s, | last day: %s <br>", $date->format('F Y'), $date->format('d'), $date->format('t'));
$date->add(new DateInterval('P1M'));
$i++;
}
Output:
December 2015 - first day: 01, | last day: 31
January 2016 - first day: 01, | last day: 31
February 2016 - first day: 01, | last day: 29
Upvotes: 4