使用序数值时使用php strtotime函数问题

时间:2011-01-25 20:06:17

标签: php strtotime

当使用strtotime的序数值时,我有时会得到意想不到的结果。例如,为什么

date("M j", strtotime("second Tuesday February 2011"))

导致“2月15日”(实际上是2011年的第三周二?

3 个答案:

答案 0 :(得分:5)

你错过了'of'。

  

$ php -r'回音日期(“M j”,strtotime(“2011年2月2日星期二”));'
  2月15日

     

$ php -r'回音日期(“M j”,strtotime(“2011年2月第二个星期二”));'
  2月8日

PHP版本:

  

$ php -v
  PHP 5.3.3(cli)(建于2010年8月22日19:41:55)
  版权所有(c)1997-2010 PHP小组
  Zend Engine v2.3.0,版权所有(c)1998-2010 Zend Technologies

documentation告诉你原因:

  

同时观察“序数”中的“of”   空间日名空间''和''最后'   空间日名空间'''确实如此   特别的东西。

     
      
  • 它将日期设置为1。
  •   
  • “ordinal dayname”的“不”   前进到另一天。 (例:   “2008年7月的第一个星期二”意味着   “2008-07-01”)。
  •   
  • “ordinal dayname”确实如此   前进到另一天。 (例:   “2008年7月的第一个星期二”意味着   “2008-07-08”,另见第4点   上面的列表)。
  •   

答案 1 :(得分:2)

manual for strtotime()告诉您的搜索内容

  

在5.2.7之前的PHP 5中,请求a   在给定的工作日发生   那个工作日的一个月   这个月的第一天会   错误地添加一周到   返回时间戳。这一直是   在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>';

答案 2 :(得分:0)

似乎依靠strtotime处理序数日期计算是不安全的 - 至少在PHP的版本中&lt; 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) );
}