So here is an interesting problem I learned today.
I need to populate an array with the last 12 months, starting with the past month. So in August 2011, the last 12
I'd like to propose an alternative solution using DatePeriod instead.
There are a number of caveats to watch out for here. For one, you don't want things like Timezone information, or day/time information to get in your way. You're only interested in the month. So we can normalize some of this information to prevent complications like overflows and daylight savings complications, etc... Since you could easily fall into this trap only on specific dates/times when these rare events occur.
$start = new DateTime;
$start->setDate($start->format('Y'), $start->format('n'), 1); // Normalize the day to 1
$start->setTime(0, 0, 0); // Normalize time to midnight
$start->sub(new DateInterval('P12M'));
$interval = new DateInterval('P1M');
$recurrences = 12;
foreach (new DatePeriod($start, $interval, $recurrences, true) as $date) {
echo $date->format('F, Y'), "\n"; // attempting to make it more clear to read here
}
Output:
February, 2019 March, 2019 April, 2019 May, 2019 June, 2019 July, 2019 August, 2019 September, 2019 October, 2019 November, 2019 December, 2019 January, 2020
I think this will work:
$this_month = date("n", time());
$this_year = date("Y", time());
$months_array = array();
for ($i = $this_month - 1; $i > ($this_month - 13); $i--) {
echo "$i<br>";
if ($i < 1) {
$correct_month_number = $i + 12;
$months_array[] = array($correct_month_number, $this_year - 1);
}
else {
$months_array[] = array($i, $this_year);
}
}
echo "<pre>"; var_dump($months_array); echo "</pre>";
The data types are a little loose, but this gets the job done. The nice thing about this is that it only calls the date() function for the current month and year, once. The rest of the logic is just simple math. No need to worry about the length of each month.
Then you can use the $months_array array to build whatever you need.
It's because not every month has a 31st. So strtotime()
is advancing to the next month. i.e. 4/31 = 5/1.
You'd be better off using mktime()
for this as it's dumber than strtotime()
.
To take advantage of a smart function like strtotime()
and avoid tracking the year for mktime()
, the following is my suggestion:
$month = time();
for ($i = 1; $i <= 12; $i++) {
$month = strtotime('last month', $month);
$months[] = date("r", $month);
}
print_r($months);
Adjust logic and optimize as you see fit.
I'm sure someone has a more elegant solution, but you could start counting backwards from the 1st of this month.
for ($i = 1; $i <= 12; $i++) {
$months[] = date("Y-m%", strtotime( date( 'Y-m-01' )." -$i months"));
}
The joys of different month lengths. strtotime is being literally, and taking 'Aug 31' and tryinn to make "Sep 31", which doesn't exist. So you end up with Oct 1 or something. A safer approach is this:
for ($i = 1; $i <= 12; $i++) {
$months[] = date("Y-m%", mktime(0, 0, 0, $i, 1, 2011));
}
strtotime is magical sometimes, but it's not reliable and certainly not "fast".