在 strtotime 中使用序数值时,我有时会得到意想不到的结果。例如,为什么
date("M j", strtotime("second Tuesday February 2011"))
结果是“Feb 15”(实际上是 2011 年的第三个星期二?
你缺少一个'of'。
$ php -r 'echo date("M j", strtotime("2011 年 2 月第二个星期二"));'
2月15日$ php -r 'echo date("M j", strtotime("2011年2月第二个星期二"));'
2月8日
PHP版本:
$ php -v
PHP 5.3.3 (cli) (build: Aug 22 2010 19:41:55)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
该文档告诉您原因:
还要注意“序数空间 dayname space 'of'”和“'last' space dayname space 'of'”中的“of”做了一些特别的事情。
- 它将日期设置为 1。
- "ordinal dayname 'of'" 不会提前到另一天。(例如:“2008 年 7 月的第一个星期二”表示“2008-07-01”)。
- “ordinal dayname”确实提前到另一天。(例如:“2008 年 7 月第一个星期二”表示“2008-07-08”,另请参见上面列表中的第 4 点)。
strtotime()的手册告诉你你在寻找什么
在 5.2.7 之前的 PHP 5 中,如果该工作日是该月的第一天,则请求在一个月内出现给定的工作日会错误地将一周添加到返回的时间戳。这已在 5.2.7 及更高版本中得到纠正。
简而言之,这是您正在使用的版本中的一个错误。
如果您正在寻找某种适用的修复,删除序数值似乎有效(好像第一个/第二个/第三个表示整周)
echo date("M j", strtotime("Tuesday February 2011")), '<br>';
echo date("M j", strtotime("first Tuesday February 2011")), '<br>';
echo date("M j", strtotime("second Tuesday February 2011")), '<br>';
echo date("M j", strtotime("third Tuesday February 2011")), '<br>';
似乎依靠 strtotime 来处理序数日期计算是不安全的——至少在 PHP < 5.3 的版本中是这样。(我已经用 5.2.9 和 5.2.11 进行了测试,尽管在线文档中声称该错误已在 5.2.7 中修复,但两者都不起作用。)
按照建议添加“of”显然仅适用于 php 5.3+ 并完全删除序数将返回“第一次”出现,但其他序数将休息 7 天。
PHP 5.2 的最佳解决方案似乎是这样的:
$recurrOrdinal = "last";
$dayOfWeek = "Thursday";
$monthYear = "March 2011";
echo ordinalDate($recurrOrdinal, $dayOfWeek, $monthYear);
function ordinalDate($recurrOrdinal, $dayOfWeek, $monthYear) {
$firstDate = date("j", strtotime($dayOfWeek . " " . $monthYear) );
if ($recurrOrdinal == "first")
$computed = $firstDate;
elseif ($recurrOrdinal == "second")
$computed = $firstDate + 7;
elseif ($recurrOrdinal == "third")
$computed = $firstDate + 14;
elseif ($recurrOrdinal == "fourth")
$computed = $firstDate + 21;
elseif ($recurrOrdinal == "last") {
if ( ($firstDate + 28) <= date("t", strtotime($monthYear)) )
$computed = $firstDate + 28;
else
$computed = $firstDate + 21;
}
return date("Y-m-d", strtotime($computed . " " . $monthYear) );
}