为什么此日期功能仅在2016年12月30日之前有效?

Sai*_*son 4 php

我有这个代码:

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>';

}
Run Code Online (Sandbox Code Playgroud)

到目前为止,它产生:

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
Run Code Online (Sandbox Code Playgroud)

但是今天(2016年12月31日),所有这些都搞砸了:

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
Run Code Online (Sandbox Code Playgroud)

2016年12月31日有什么问题?为什么我的代码搞砸了?谢谢.

bis*_*hop 6

您的代码失败了:

$february = strtotime('February');
echo date(DATE_ISO8601, $february);
Run Code Online (Sandbox Code Playgroud)

其中今天,2016年12月30日的输出:

2016-03-01T00:00:00+0000
Run Code Online (Sandbox Code Playgroud)

嗯......为什么PHP说"二月"是"2016-03-01"?好吧,它与PHP如何填补缺失信息的空白有关:在没有明确给定绝对时间值的情况下,PHP使用当前日期和时间的值.

因此,由于它是12月30日东部时间13:29,以下是语义等价的:

strtotime('February');                       // you asked for
strtotime('February 30, 2016 13:29:47 EST'); // PHP interprets as
//                  ^^^^^^^^^^^^^^^^^^^^^ filled in from current time
Run Code Online (Sandbox Code Playgroud)

显然,后者,解释日期是假的.PHP(通过底层库,实际上)使用2月30日= 2月29日+ 1天= 3月1日的逻辑来转换解释日期.(更糟糕的是,在像2017年的非闰年,PHP将计算2月30日= 2月28日+ 2天= 3月2日,输出为"2017-03-02T00:00:00 + 0000"!)

因此,在您要求PHP进行日期转换时,在这些情况下,您需要做的是明确的.这意味着不要求strtotime('February');你要求:

$year = date('Y');
$date_established = strtotime("$monthName 1, $year");
Run Code Online (Sandbox Code Playgroud)

(或等效.重点是:不要让PHP用当前日期的值填充缺少的信息.)

除此之外:这些错误特别难以追踪,因为当月的当前日期小于所要求的月份的天数时,代码"有效" .根据我的经验,strtotime除非你绝对需要,否则最好避免,当你绝对需要时,你尽可能多地提供明确的信息.

  • 你打败了我.也许更好的选择是使用`mktime()`来制作`$ date_established`,而不是`strtotime()`. (2认同)