Проблема с функцией php strtotime при использовании порядковых значений

Я когда-нибудь получаю неожиданные результаты при использовании порядковых значений с strtotime. Например, почему

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

приведет к «15 февраля» (что на самом деле является третьим вторником в 2011 году?

Вам не хватает «of».

$ php -r 'echo date («M j», strtotime («второй вторник февраля 2011 года»));
15 февраля

$ php -r 'echo date («M j», strtotime («второй вторник февраля 2011 года»));
8 февраля

Версия PHP:

$ php -v
PHP 5.3.3 (cli) (построен: 22 августа 2010 19:41:55)
Copyright (c) 1997-2010 PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

Документация говорит вам причину этого:

Также обратите внимание на то, что «из» в «пространственном пространстве« пространство имен »пространства« »и« последний »пространство« имя дня »пространства« »делает что-то особенное.

  • Он устанавливает день месяца в 1.
  • «ordinal dayname» of «» не продвигается к другому дню. (Пример: «первый вторник июля 2008 года» означает «2008-07-01»).
  • «порядковое имя дня» продвигается к другому дню. (Пример: «первый вторник, июль 2008» означает «2008-07-08», см. Также пункт 4 в приведенном выше списке).

Руководство для strtotime () сообщает, что вы ищете

В PHP 5 до 5.2.7 запрос на заданное вхождение данного дня недели в месяц, когда этот день недели был первым днем ​​месяца, неправильно добавит одну неделю к возвращенной отметке времени. Это было исправлено в 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.)

Добавление «из», как было предложено, по-видимому, работает только в 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("Ymd", strtotime($computed . " " . $monthYear) ); }