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