0

I have some strange behaviour happening when I run the following on the last day of May (31st). If I change my system time to 30th May, or the last day of say, June (30th), it functions normally.

For some reason though, on the 31st, it will skip the next month (June), and instead replace it with July. So it will output July twice. Here is an example:

31 days in 05, 31 days in 07, 31 days in 07, 31 days in 08,

Code which generated the above

<?php
$datepicker_month_range = 3;

// create an array of dates for a number of months specified by the user. 0 is used for this month
for ($month = 0; $month <= $datepicker_month_range; $month++) {
  $dt_dates = new DateTime();
  $dt_dates->add(new DateInterval("P{$month}M")); // example, P1M == plus 1 month
  $days_in_month = cal_days_in_month(CAL_GREGORIAN, $dt_dates->format('m'), $dt_dates->format('Y'));

  echo $days_in_month." days in ".$dt_dates->format('m').", ";

  for ($day = 1; $day <= $days_in_month; $day++) {
    $date = $dt_dates->format('Y')."-".$dt_dates->format('m')."-".sprintf('%02d', $day); // leading zeros 05-..
    $month_days[] = $date; 
  }
}
//print_r($month_days);
?>

Later on, if print_r($month_days) is run, the complete dates are outputted with July outputted twice like in the previous expression.

What is causing this behaviour?

Thanks.

user3442612
  • 1,802
  • 6
  • 22
  • 27
  • 2
    [See example #3: beware when adding months.](http://php.net/manual/en/datetime.add.php#refsect1-datetime.add-examples) – Don't Panic May 31 '17 at 22:31
  • 1
    This is the expected behavior when adding months. If the date is `31-May` and you add 1 month, it literally increments the month value from `05` to `06`, but the day stays the same. Since there is no `31-Jun`, that is then rolled over to `01-Jul`. All the date/time functions will "roll over" invalid values like this. `40-Jun` is considered `10 days past the last day of june` and would roll over to `10-Jul`. – Jonathan Kuhn May 31 '17 at 22:54
  • Thanks, I see the problem now. I guess an easier fix would be to rollback the date to the 1st, then modify later code that was reliant on it being the current date. – user3442612 Jun 01 '17 at 07:13

1 Answers1

0

Ok, after reading the comments, it seems this is a duplicate of PHP DateTime::modify adding and subtracting months

but here is how I got around the problem.

$month_beginning = $dt_dates->format('Y-m-01');
$dt_dates = new DateTime($month_beginning); // rollback the date to the first so we can increment months safely

All together

for ($month = 0; $month <= $datepicker_month_range; $month++) {
  $dt_dates = new DateTime();
  $month_beginning = $dt_dates->format('Y-m-01');
  $dt_dates = new DateTime($month_beginning); // rollback the date to the first so we can increment months safely
  $dt_dates->add(new DateInterval("P{$month}M")); // P1M == plus 1 month
  $days_in_month = cal_days_in_month(CAL_GREGORIAN, $dt_dates->format('m'), $dt_dates->format('Y'));
  //echo $days_in_month." days in ".$dt_dates->format('m').", ";
  for ($day = 1; $day <= $days_in_month; $day++) {
    $date = $dt_dates->format('Y')."-".$dt_dates->format('m')."-".sprintf('%02d', $day); // leading zeros 05-..
    $month_days[] = $date; // holds dates for datepicker month ranges
  }
}
user3442612
  • 1,802
  • 6
  • 22
  • 27