I have this code :
for ($i=1; $i<=12; $i++) {
$monthNum = $i;
$monthName = date('F', mktime(0, 0, 0, $monthNum, 10));
$date_established = strtotime($monthName);
$date_established = strtotime('first day of this month', $date_established);
$date_established = date('Y-m-d', $date_established);
$date_established_end = date("Y-m-t", strtotime($date_established));
echo $i .'::'. $monthName . '::' . $date_established . '::' . $date_established_end . '<br>';
}
and so far, it produces :
1::January::2016-01-01::2016-01-31
2::February::2016-02-01::2016-02-28
3::March::2016-03-01::2016-03-31
4::April::2016-04-01::2016-04-30
5::May::2016-05-01::2016-05-31
6::June::2016-06-01::2016-06-30
7::July::2016-07-01::2016-07-31
8::August::2016-08-01::2016-08-31
9::September::2016-09-01::2016-09-30
10::October::2016-10-01::2016-10-31
11::November::2016-11-01::2016-11-30
12::December::2016-12-01::2016-12-31
but today (31 December 2016), all messed up like this :
1::January::2016-01-01::2016-01-31
2::February::2016-03-01::2016-03-31
3::March::2016-03-01::2016-03-31 << duplicate
4::April::2016-05-01::2016-05-31
5::May::2016-05-01::2016-05-31 << duplicate
6::June::2016-07-01::2016-07-31
7::July::2016-07-01::2016-07-31 << duplicate
8::August::2016-08-01::2016-08-31
9::September::2016-10-01::2016-10-31
10::October::2016-10-01::2016-10-31 << duplicate
11::November::2016-12-01::2016-12-31
12::December::2016-12-01::2016-12-31 << duplicate
what's wrong with 31 December 2016? why my code messed up? thank you.
Your code fails along these lines:
$february = strtotime('February');
echo date(DATE_ISO8601, $february);
which today, December 30, 2016 outputs:
2016-03-01T00:00:00+0000
Hmmm... why is PHP saying that "February" is "2016-03-01"? Well, it has to do with how PHP fills in the gaps for missing information: in the absence of explicitly given absolute time values, PHP uses the current date and time's values.
Thus, since it's December 30 at 13:29 Eastern, the following are semantically equivalent:
strtotime('February'); // you asked for
strtotime('February 30, 2016 13:29:47 EST'); // PHP interprets as
// ^^^^^^^^^^^^^^^^^^^^^ filled in from current time
Clearly that latter, interpretted date is bogus. PHP (via the underlying library, actually) shifts the interpretted date using the logic that Feb 30 = Feb 29 + 1 day = Mar 1. (Worse, in a non-leap year like 2017, PHP would calculate Feb 30 = Feb 28 + 2 days = Mar 2, and the output would be "2017-03-02T00:00:00+0000"!)
So, what you need to do, under these circumstances, is be explicit when you're asking PHP for date conversion. That means instead of asking for strtotime('February');
you ask for:
$year = date('Y');
$date_established = strtotime("$monthName 1, $year");
(or equivalent. The point being: don't let PHP fill in the missing information with the current date's values.)
Aside: These bugs are particularly hard to track down, because the code "works" when the current day of the month is less than the number of days in the month asked for. In my experience, it's best to avoid strtotime
unless you absolutely need, and when you do absolutely need it, you give it as much explicit information as possible.
Not sure why this is happening, but it's easy enough to work around:
for ($i=1; $i<=12; $i++) {
$monthNum = sprintf("%02d", $i);
$monthName = date('F', mktime(0, 0, 0, $monthNum, 10));
$date_established = date("Y-$monthNum-01");
$date_established_end = date("Y-m-t", strtotime($date_established));
echo "$i :: $monthName :: $date_established :: $date_established_end <br>\n";
}
You always know that the first of the month is going to be "01" so just specify it directly.
Edit: clearly someone else knows why it's happening!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With