开发者

Get the last 12 months in PHP

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 months will be Sep 2010 - July 2011. To do this, I am using:

for ($i = 1; $i <开发者_如何学Python= 12; $i++)
    $months[] = date("Y-m%", strtotime("-$i months"));

The code above works just fine on August 30. I get the last 12 months:

array
    0 => string '2011-07%' (length=8)
    1 => string '2011-06%' (length=8)
    2 => string '2011-05%' (length=8)
    3 => string '2011-04%' (length=8)
    4 => string '2011-03%' (length=8)
    5 => string '2011-02%' (length=8)
    6 => string '2011-01%' (length=8)
    7 => string '2010-12%' (length=8)
    8 => string '2010-11%' (length=8)
    9 => string '2010-10%' (length=8)
    10 => string '2010-09%' (length=8)
    11 => string '2010-08%' (length=8)

But when I run this on Aug 31, I get:

array
    0 => string '2011-07%' (length=8)
    1 => string '2011-07%' (length=8)
    2 => string '2011-05%' (length=8)
    3 => string '2011-05%' (length=8)
    4 => string '2011-03%' (length=8)
    5 => string '2011-03%' (length=8)
    6 => string '2011-01%' (length=8)
    7 => string '2010-12%' (length=8)
    8 => string '2010-12%' (length=8)
    9 => string '2010-10%' (length=8)
    10 => string '2010-10%' (length=8)
    11 => string '2010-08%' (length=8)

I have tried both Windows and Unix. Does anyone have a solution for this?


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"));
}


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().

UPDATE

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'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.


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".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜