2010-12-10 6 views
31

кодекс говорит миллион слов:PHP DateTime :: createFromFormat не разобрать ISO 8601 дата время

php > echo strtotime("2010-12-07T23:00:00.000Z"); 
1291762800 
echo date('c', 1291762800); 
2010-12-08T00:00:00+01:00 
php > var_dump(DateTime::createFromFormat('c', "2010-12-07T23:00:00.000Z")); 
bool(false) 
php > var_dump(DateTime::createFromFormat(DateTime::ISO8601, "2010-12-07T23:00:00.000Z")); 
bool(false) 

Любая идея, что происходит?

Btw, да, новый DateTime ("2010-12-07T23: 00: 00.000Z") отлично работает. Но я предпочитаю знать, какой вклад я получаю.

+3

Ваши доли секунды не являются частью формата. 'DateTime :: ISO8601' - это строка со значением' Y-m-d \ TH: i: sO'. – salathe

+4

WikiPedia не согласен: Десятичные фракции также могут быть добавлены к любому из трех элементов времени. Десятичная точка, либо запятая, либо точка (без каких-либо предпочтений, как было заявлено совсем недавно в резолюции 10 22-й Генеральной конференции CGPM в 2003 году), используется как разделитель между элементом времени и его дробью. Фракция может быть добавлена ​​только к элементу времени наименьшего порядка в представлении. – Jake

+0

'public static DateTime DateTime :: createFromFormat (строка $ format, string $ time [, DateTimeZone $ timezone])', возможно, вызвана включением часового пояса – ajreal

ответ

32

Там в сообщение об ошибке, которая точно описывает вашу проблему :)

https://bugs.php.net/bug.php?id=51950

С 2016-08-07, отчет об ошибке был отмечен как «не ошибка». Вместо этого вам нужно использовать strtotime или new DateTime.

Константы, которые были определены, применяются как к форматированию, так и к синтаксическому анализу таким же образом, что заставляет ваши пути.

+2

Действительно разочаровывает. Зачем называть константу «ISO8601», если она не соответствует этому стандарту. Вот почему мне не нравится PHP много. – jlh

+0

Кровавый 7 лет спустя, и это все еще существует .... и даже обозначено как не ошибка? 'Если вы хотите принять разные форматы даты и времени ISO-8601'. Различные форматы ISO-8601? Почему я не люблю php в двух словах. –

+0

Чувство боли тоже –

1

Очень странно и неутешительно, что эта ошибка по-прежнему актуальна. Вот правильный шаблон для разбора даты с микросекунд в десятичной части секунды:

Y-m-d\TH:i:s.uO 

Использование:

$dateStr = '2015-04-29T11:42:56.000+0400' 
$ISO = 'Y-m-d\TH:i:s.uO' 
$date = DateTime::createFromFormat($ISO, $dateStr) 
+1

На самом деле, эта работа работает только в том случае, если присутствует десятичная часть секунд. Более того, он работает только в том случае, если имеется только от 1 до 6 цифр точности. Если десятичная часть опущена или, если она точнее, возвращается false. – Glutexo

6

попробовать это:

даты
DateTime::createFromFormat('Y-m-d\TH:i:sP', $date) 
10

Синтаксический ISO8601, а также переключение часовой пояс:

// create ISO8601 dateTime 
$date = DateTime::createFromFormat(DateTime::ISO8601, '2016-07-27T19:30:00Z'); 

// set to user's timezone 
$date -> setTimeZone('Asia/Singapore'); 

echo $date -> format(DateTime::ISO8601); 
// prints '2016-07-28T03:30:00+0800' 
+0

скопировал ваш код, и он печатает: «2016-07-27T19: 30: 00 + 0000» с использованием PHP 5.6.10. –

+0

@AlexAngelico. Каков результат для 'echo DateTime :: ISO8601;'? Он печатает 'Y-m-d \ TH: i: sO' для меня. – a20

+0

yes, DateTime :: ISO8601 печатает Y-m-d \ TH: i: sO Я использую этот код, чтобы изменить время на правильный часовой пояс. Я нахожусь в GMT-5 '$ fecha_str = '2017-04-12T21: 43: 54 + 02: 00'; \t $ date = strtotime ($ fecha_str); \t echo date ("Y-m-d h: i: s", $ date); \t/output => 2017-04-12 07:43:54 ' –

2

Никто не упомянул использовать DATE_ATOM, который, насколько я знаю ПГПС наиболее правильное внедрение ISO 8601. Он должен, по крайней мере, работа за последние 3 из них:

<?php 

$dates = array(
    "2010-12-07T23:00:00.000Z", 
    "2010-12-07T23:00:00", 
    "2010-12-07T23:00:00Z", 
    "2010-12-07T23:00:00+01:00", 
    (new \DateTime("now"))->format(DATE_ATOM) 
); 

foreach($dates as $d) { 

    $res = \DateTime::createFromFormat(DATE_ATOM, $d); 

    echo "try $d: \n"; 
    var_dump($res); 
    echo "\n\n"; 
} 

?> 

Чтобы иметь возможность проанализировать все из них я написал маленькую функцию:

<?php 

function parse_iso_8601($iso_8601_string) { 
    $results = array(); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:s",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:s.u",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:s.uP",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat("Y-m-d\TH:i:sP",$iso_8601_string); 
    $results[] = \DateTime::createFromFormat(DATE_ATOM,$iso_8601_string); 

    $success = array_values(array_filter($results)); 
    if(count($success) > 0) { 
     return $success[0]; 
    } 
    return false; 
} 

// Test 
$dates = array(
    "2010-12-07T23:00:00.000Z", 
    "2010-12-07T23:00:00", 
    "2010-12-07T23:00:00Z", 
    "2010-12-07T23:00:00+01:00", 
    (new \DateTime("now"))->format(DATE_ATOM) 
); 

foreach($dates as $d) { 

    $res = parse_iso_8601($d); 

    echo "try $d: \n"; 
    var_dump($res); 
    echo "\n\n"; 
} 

?> 

Как @Glutexo упомянуто, что он работает только тогда, когда есть только 1 до 6 точности цифр для десятичной части тоже. Не стесняйтесь улучшать его.

0

Для ответа, приведенного здесь https://stackoverflow.com/a/14849503/2425651 , мы можем использовать этот формат «Y-m-d \ TH: i: s.u +» для сохранения микросекунд.

$format = 'Y-m-d\TH:i:s.u+'; 
$value = '2017-09-21T10:11:19.026Z'; // jsDate.toUTCString(); 
var_dump(\DateTime::createFromFormat($format, $value)); 
0

Это один работает для меня:

$date = (new DateTime)->setTimestamp(strtotime('2017-12-31T23:00:00.000Z')); 
Смежные вопросы