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?
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?
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).
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>';
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) );
}