Jonty Behr  •  05 Feb 2017

Adding or Subtracting Months in PHP

Working with dates in PHP can get interesting sometimes, especially if you're trying to calculate the end of a month.

First things first - if you're working with dates in PHP, then you should almost certainly use Carbon. Its just ridiculously easy to use and the abstractions that it provides will make your coding life much much easier. Laravel uses Carbon out of the box for good reason.

We've come up against strange (i.e. unexpected) "end of month" calculations in PHP before. For example, lets say that you're trying to create an interval of months, and you want the end date of each month, starting with the month of January.

$startDate = \Carbon\Carbon::create(2016, 1, 1);
$endOfMonth = $startDate->copy()->endOfMonth(); // 2016-01-31

// lets get the end of the next month
$endOfFebruary = $endOfMonth->copy()->addMonth(); // 2016-03-02 ??

On the face of it, this looks like we should just get 2016-02-29 (or 28 if its a non-leap year). But this is not how Carbon works; or PHP for that matter, bearing in mind that Carbon is really a wrapper around PHP's native DateTime API. Instead, the above will actually output 2016-03-02 23:59:59, which is clearly wrong!

There are a few ways around this, but we've found the easiest way is the following:

$endOfFebruary = $endOfMonth->copy()->startOfMonth()->addMonth()->endOfMonth();

What we're doing here is first manipulate the date to startOfMonth(), and only after that do we addMonth() and then change it to endOfMonth(). By following this order of operations, we ensure that we always get the correct end of month.

Working with dates in PHP can get really interesting (and if you add in Timezones, boy-oh-boy are you in for a fun time), but using Carbon can really help simplify things, especially in situations like this.