Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP DateInterval not returning last day of the month

I'm using the following code:

public static function getDays($day, $m, $y) {
  $days = new DatePeriod(
    new DateTime("first $day of $m $y"),
    DateInterval::createFromDateString('next ' . $day),
    new DateTime("last day of $m $y")
  );
  foreach ($days as $day) {
    $dates[] = $day->format("Y-m-d");
  }
  return $dates;
}

It work's for the most part. I give it a range and it returns the date of each day I am after inside the range.

Usage:

foreach(General::getDays('friday',$this->_uri[2],$this->_uri[3]) as $date) {
  var_dump($date);
}

In July 2013, this returns the correct 4 results, all friday's in July 2013:

string '2013-07-05' (length=10)
string '2013-07-12' (length=10)
string '2013-07-19' (length=10)
string '2013-07-26' (length=10)

However, on a month that the last day is a match to the day occurance I am after (friday for example, May 2013 and January 2014) it misses the last day of the month out of the returned results.

May 2013 results, missing of course the 31st which is a friday:

string '2013-05-03' (length=10)
string '2013-05-10' (length=10)
string '2013-05-17' (length=10)
string '2013-05-24' (length=10)

Does anyone have an answer for this? Is this my miss-use of DateInterval or a genuine fault in this class?

like image 748
lukeocodes Avatar asked Jul 26 '13 21:07

lukeocodes


People also ask

How do you get the last day of the month in PHP?

$date = strtotime ( $datestring ); // Last date of current month. $day = date ( "l" , $lastdate );

What is date interval?

The span of time between a specific start date and end date.

What is DateInterval in PHP?

The DateInterval::format() function is used to format the interval.


1 Answers

The problem is that the end date/time itself is never included in the period -- that is, the DatePeriod object represents date/times in the [$startDate, $endDate) range¹.

You have to add one second at least to the end date to always get the expected results. But let's not be stingy and add a whole minute:

$days = new DatePeriod(
    new DateTime("first $day of $m $y"),
    DateInterval::createFromDateString('next ' . $day),
    new DateTime("last day of $m $y 00:01")
);

¹ unless you use the DatePeriod::EXCLUDE_START_DATE option, in which case the start date itself is excluded as well

like image 147
Jon Avatar answered Oct 06 '22 00:10

Jon