Issue with php strtotime function when using ordinal values

眉间皱痕 提交于 2019-12-21 18:04:20

问题


I sometime get unexpected results when using ordinal values with strtotime. For example, why does

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

result in "Feb 15" (which is actually the third Tuesday in 2011?


回答1:


You are missing an 'of'.

$ php -r 'echo date("M j", strtotime("second Tuesday February 2011"));'
Feb 15

$ php -r 'echo date("M j", strtotime("second Tuesday of February 2011"));'
Feb 8

PHP Version:

$ php -v
PHP 5.3.3 (cli) (built: Aug 22 2010 19:41:55)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

The documentation tells you the cause for this:

Also observe that the "of" in "ordinal space dayname space 'of' " and "'last' space dayname space 'of' " does something special.

  • It sets the day-of-month to 1.
  • "ordinal dayname 'of' " does not advance to another day. (Example: "first tuesday of july 2008" means "2008-07-01").
  • "ordinal dayname " does advance to another day. (Example: "first tuesday july 2008" means "2008-07-08", see also point 4 in the list above).



回答2:


The manual for strtotime() tells what you seek

In PHP 5 prior to 5.2.7, requesting a given occurrence of a given weekday in a month where that weekday was the first day of the month would incorrectly add one week to the returned timestamp. This has been corrected in 5.2.7 and later versions.

In short, it's a bug in the version you're using.

If you're looking for some sort of applicable fix, dropping the ordinal value seems to work (as if the first/second/third indicate full weeks)

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



回答3:


It seems that it's not safe to rely on strtotime to deal with ordinal date computations -- at least in versions of PHP < 5.3. (I've tested with 5.2.9 and 5.2.11 and neither works despite the claim in the online documentation that the bug was fixed in 5.2.7.)

Adding "of" as suggested apparently only works in php 5.3+ and dropping the ordinal altogether will return the "first" occurrence, but other ordinals will be 7 days off.

The best solution for PHP 5.2 seems to be something like this:

$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) );
}


来源:https://stackoverflow.com/questions/4798261/issue-with-php-strtotime-function-when-using-ordinal-values

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!