Форматирование даты и времени и часовой пояс - PullRequest
4 голосов
/ 24 января 2012

При попытке анализа даты с DateTime::createFromFormat PHP не распознает часовой пояс.

Пример:

$t = new \DateTime(); 
echo $t->format('Y-m-dTH:i:s');

выведет

2012-01-24MSK16:53:52

Теперь, когдаЯ пытаюсь разобрать эту строку из того же формата

var_dump(\DateTime::createFromFormat('Y-m-dTH:i:s', '2012-01-24MSK16:53:52'));

Я получаю

bool(false)

Когда я не помещаю часовой пояс в строку, это работает

$t = new \DateTime(); 
echo $t->format('Y-m-dH:i:s');

даст

2012-01-2417:17:24

и синтаксический анализ, который

var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', "2012-01-2417:17:24"));

даст

object(DateTime)#3 (3) {
  ["date"]=>
  string(19) "2012-01-24 17:17:24"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Moscow"
}

Проверено на

  • PHP 5.3.6-13ubuntu3.3 с Suhosin-Patch (cli) (сборка: 13 декабря 2011 18:18:37) и
  • PHP 5.3.9 (cli) (сборка: 18 января 2012 20:02:33)

Проблема появляется, только если мы позаботимся о часовом поясе.Это ошибка?Или что я делаю не так?Заранее спасибо!

Ответы [ 2 ]

14 голосов
/ 24 января 2012

Это похоже на ошибку (или, по крайней мере, недокументированное ограничение ) с PHP ... Если мы попробуем 4 возможных перестановки пробелов:

var_dump(\DateTime::createFromFormat('Y-m-dTH:i:s', '2012-01-24MSK16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-d T H:i:s', '2012-01-24 MSK 16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-d TH:i:s', '2012-01-24 MSK16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-dT H:i:s', '2012-01-24MSK 16:53:52'));

Получаем (проверено PHP 5.3, 5.4rc6 и Trunk):

bool(false)
object(DateTime)#2 (3) {
  ["date"]=>
  string(19) "2012-01-24 16:53:52"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(3) "MSK"
}
bool(false)
object(DateTime)#3 (3) {
  ["date"]=>
  string(19) "2012-01-24 16:53:52"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(3) "MSK"
}

Похоже, это указывает на то, что идентификатор часового пояса и / или час чувствительны к пробелам ... Тестирование далее:

var_dump(\DateTime::createFromFormat('Y-m-d H:i:s', '2012-01-24 16:53:52'));
var_dump(\DateTime::createFromFormat('Y-m-dH:i:s', '2012-01-2416:53:52'));

Дает надлежащие результаты. И:

var_dump(\DateTime::createFromFormat('TY-m-d', 'MSK2012-01-24'));
var_dump(\DateTime::createFromFormat('T Y-m-d', 'MSK 2012-01-24'));

Урожайность:

bool(false)
object(DateTime)#4 (3) {
  ["date"]=>
  string(19) "2012-01-24 01:49:26"
  ["timezone_type"]=>
  int(2)
  ["timezone"]=>
  string(3) "MSK"
}

Так что да, похоже, что спецификатор часового пояса чувствителен к конечным пробелам ...

Редактировать: чувствительно к пробелам

Если мы посмотрим на parse_date.c timelib_parse_from_format() в строке 25075 , мы увидим, что все 4 формата часовых поясов анализируются одинаково! Это означает, что нет никакой разницы между идентификаторами формата для разбора, и поэтому для разбора они взаимозаменяемы.

Само по себе это кажется достаточной ошибкой (или отсутствием функции) для продолжения. Но давайте посмотрим, что происходит в timelib_get_zone(), который вызывается при использовании идентификатора часового пояса. Ну, посмотрим, мы можем видеть, что мы вызываем timelib_lookup_zone(), когда это не время по Гринвичу или временной сдвиг.

И там мы нашли ошибку. В строке 768 из timelib_lookup_zone мы можем видеть, что она будет использовать всю входную строку, вплоть до \0 (ноль), ) или пробела:

while (**ptr != '\0' && **ptr != ')' && **ptr != ' ') {
    ++*ptr;
}

Что касается исправления, это немного сложнее. Чтобы просто решить эту проблему, потребуется повторно реализовать синтаксические анализаторы формата для каждого часового пояса. Для парсера T это легко, так как это всегда трёхбуквенная строка. Но для других это немного интереснее, так как есть переменные буквы, и поэтому может возникнуть проблема с чувствительностью пробела.

Короче, я бы предложил просто добавить конечный пробел к вашим идентификаторам часовых поясов и покончить с этим ...

0 голосов
/ 24 января 2012

Вы можете проверить, имеет ли ваш php.ini значение по умолчанию для date.timezone, и если не использовать, date_default_timezone_set , поскольку DateTime полагается на него.

...