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


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

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

Результат "15 февраля" (который на самом деле является третьим вторником в 2011 году?

3 4

3 ответа:

Вы пропускаете "оф".

$ 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 The PHP Group
Зенд двигателя V2.3.0, Авторское право (c) 1998-2010 Зенд технологий

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

Также заметьте, что" из "в" порядковом пространство dayname пространство 'of' и 'last' пространство dayname " и "" не нечто особенное.

    Он устанавливает день месяца равным 1.
  • "порядковый номер дня '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

Добавление "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) );
}