PHP DateTime::createFromFormat analysiert die ISO 8601-Datumszeit nicht

Lesezeit: 6 Minuten

Benutzer-Avatar
Jake

Code spricht mehr als eine Million Worte:

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)

Irgendeine Ahnung, was los ist?

Übrigens, ja, das neue DateTime (“2010-12-07T23:00:00.000Z”) funktioniert einwandfrei. Aber ich ziehe es vor zu wissen, welchen Input ich bekomme.

  • Ihre Sekundenbruchteile sind nicht Teil des Formats. DateTime::ISO8601 ist ein String mit dem Wert Y-m-d\TH:i:sO.

    – Salat

    10. Dezember 2010 um 17:53 Uhr


  • WikiPedia ist anderer Meinung: Dezimalbrüche können auch zu jedem der drei Zeitelemente hinzugefügt werden. Als Trennzeichen zwischen dem Zeitelement und seinem Bruch wird ein Dezimalpunkt verwendet, entweder ein Komma oder ein Punkt (ohne Präferenz, wie zuletzt in Resolution 10 der 22. Generalkonferenz CGPM im Jahr 2003 angegeben). Ein Bruchteil darf nur zum Zeitelement niedrigster Ordnung in der Darstellung addiert werden.

    – Jake

    10. Dezember 2010 um 18:07 Uhr

  • public static DateTime DateTime::createFromFormat ( string $format , string $time [, DateTimeZone $timezone ] )wird möglicherweise durch die Angabe der Zeitzone verursacht

    – ajreal

    10. Dezember 2010 um 18:11 Uhr

  • Anscheinend sind “c” und DateTime::ISO8601 auch nicht dasselbe: php > var_dump(DateTime::createFromFormat(‘c’, “2010-12-10T19:02:09+01:00”)); bool(false) php > var_dump(DateTime::createFromFormat(‘c’, ‘2010-12-10T19:02:09+01:00’)); bool(false) php > var_dump(DateTime::createFromFormat(DateTime::ISO8601, ‘2010-12-10T19:02:09+01:00’)); Objekt(DatumUhrzeit)#26 (3) { [“date”]=> Zeichenkette(19) “2010-12-10 19:02:09” [“timezone_type”]=> int(1) [“timezone”]=> Zeichenkette(6) “+01:00” }

    – Jake

    10. Dezember 2010 um 18:20 Uhr


Benutzer-Avatar
Jack

Es gibt einen Fehlerbericht, der Ihr Problem genau beschreibt 🙂

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

Seit 07.08.2016 ist der Fehlerbericht als „kein Fehler“ gekennzeichnet. Sie müssen verwenden strtotime oder new DateTime stattdessen.

Die definierten Konstanten gelten für die Formatierung und das Parsen in gleicher Weise, was Ihre Wege zwingt.

  • In der Tat enttäuschend. Warum eine Konstante „ISO8601“ nennen, wenn sie diesem Standard eigentlich nicht entspricht. Deshalb mag ich PHP nicht sehr.

    – jlh

    18. Oktober 2016 um 8:30 Uhr

  • Verdammte 7 Jahre später und das existiert immer noch…. und ist sogar als kein Fehler markiert? If you want to accept different ISO-8601 date/time formats. Unterschiedliche ISO-8601-Formate?? Warum ich PHP nicht mag, auf den Punkt gebracht.

    – Douglas Gaskell

    2. September 2017 um 21:45 Uhr

  • Auch den Schmerz spüren

    – Michael Ambrosius

    29. Januar 2018 um 23:36 Uhr

  • TBF, innerhalb der Designbeschränkungen von PHP ist dies tatsächlich kein Fehler. createFromFormat unterstützt nicht Optional Datumsteile. Das wäre meiner Meinung nach auch dumm zu implementieren, da die Formatbezeichner eine einfache Syntax und einen naiven Parser verwenden. PHP müsste so etwas unterstützen: Y-m-d\TH:i:s[?v]P wobei die eckigen Klammern optional bedeuten. Das muss dann wohl intern in Regex übersetzt werden. Ich werde den naiven Parser haben, danke. Wenn Sie wirklich Mikrosekunden wollen und wissen, dass dies das Format ist, das Sie erhalten, verwenden Sie Y-m-d\TH:i:s?vP. Wenn Sie mehrere Formate wünschen, verwenden Sie einfach new DateTime

    – weit

    27. Mai um 7:57 Uhr

Analysieren des ISO8601-Datums und auch Umschalten der Zeitzone:

// 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'

  • kopierte Ihren Code und er druckt: “2016-07-27T19:30:00+0000” mit PHP 5.6.10

    – Alex Angelico

    20. April 2017 um 22:02 Uhr

  • @AlexAngelico Wofür ist die Ausgabe echo DateTime::ISO8601;? Es druckt Y-m-d\TH:i:sO Für mich.

    – a20

    21. April 2017 um 6:36 Uhr


  • ja, DateTime::ISO8601 druckt Ymd\TH:i:sO Ich verwende diesen Code, um die Zeit auf die richtige Zeitzone zu ändern. Ich bin in GMT-5 $fecha_str = '2017-04-12T21:43:54+02:00'; $date = strtotime($fecha_str); echo date("Y-m-d h:i:s", $date); /output=> 2017-04-12 07:43:54

    – Alex Angelico

    21. April 2017 um 15:29 Uhr


  • Nur als Hinweis, nicht verwenden format(\DateTime::ISO8601) weil es kein gültiges ISO8601-Format ist. Verwenden Sie stattdessen entweder c, \DateTime::ATOM oder DATE_ATOM. Der Grund liegt darin, dass \DateTime:ISO8601 Weise würde falsch speichert als 2005-08-15T15:52:01+0000 tatsächlich sollte eine gültige ISO8601-Datumszeichenfolge einen Doppelpunkt zwischen der Zeitzonenkennung haben, wie z 2005-08-15T15:52:01+00:00. Dies wird in den PHP-Dokumenten erwähnt, ist aber nicht sofort klar. Lesen Sie die Dokumente hier: ca3.php.net/manual/en/…

    – puiu

    30. November 2017 um 18:49 Uhr

  • Weder \DateTime::ISO8601 noch \DateTime::ATOM funktionieren bei mir für Daten wie ‘2020-02-04T00:00:00.000Z’. Das Format ‘Ymd\TH:i:s+’ funktioniert hervorragend.

    – ed22

    28. Februar 2020 um 14:36 ​​Uhr

Niemand hat erwähnt, DATE_ATOM zu verwenden, was meines Wissens die korrekteste Implementierung von PHP von ISO 8601 ist. Es sollte zumindest für die letzten 3 davon funktionieren:

<?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";
}

?>

Um sie alle analysieren zu können, habe ich eine kleine Funktion geschrieben:

<?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";
}

?>

Wie @Glutexo erwähnt hat, funktioniert es nur, wenn auch für den Dezimalteil nur 1 bis 6 Präzisionsziffern vorhanden sind. Fühlen Sie sich frei, es zu verbessern.

  • Du bist der Mann! Ich habe so etwas gegoogelt wie “php analysiert alle RFC 8601-Formate” und zufällig Ihre Lösung gefunden. Sie hat mir sehr geholfen.

    – Serhij Popov

    9. Dezember 2018 um 19:14 Uhr

  • Wieso den? Das ist im Grunde was new DateTime tut unter der Haube…

    – weit

    27. Mai um 9:35 Uhr

Versuche dies:

DateTime::createFromFormat('Y-m-d\TH:i:sP', $date)

Es ist sehr seltsam und enttäuschend, dass dieser Fehler immer noch aktuell ist. Hier ist ein richtiges Muster zum Analysieren von Daten mit Mikrosekunden im Dezimalteil von Sekunden:

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

Verwendungszweck:

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

  • Eigentlich funktioniert das nur, wenn der Dezimalteil der Sekunden vorhanden ist. Außerdem funktioniert es nur, wenn es nur 1 bis 6 Präzisionsziffern gibt. Wird der Dezimalteil weggelassen oder ist er genauer, wird false zurückgegeben.

    – Glutexo

    2. Dezember 2015 um 13:51 Uhr

  • Seine Arbeit für mich thx!

    – Himmelswind

    20. Oktober 2021 um 20:35 Uhr

Benutzer-Avatar
stloc

Einfach :

$dt = new DateTime('2018-04-07T16:32:44Z');
$dt->format('Ymd'); // 20180407

  • Eigentlich funktioniert das nur, wenn der Dezimalteil der Sekunden vorhanden ist. Außerdem funktioniert es nur, wenn es nur 1 bis 6 Präzisionsziffern gibt. Wird der Dezimalteil weggelassen oder ist er genauer, wird false zurückgegeben.

    – Glutexo

    2. Dezember 2015 um 13:51 Uhr

  • Seine Arbeit für mich thx!

    – Himmelswind

    20. Oktober 2021 um 20:35 Uhr

Benutzer-Avatar
Johann Erk

Verwenden DATE_ATOM statt 'c' beim Formatieren wie @Steven sagte. So arbeiten Sie mit ISO 8601 in PHP.

<?php
$now_date = new DateTime();
$now_iso_8601 = $now_date->format(DATE_ATOM);
echo "Now in ISO 8601 format: {$now_iso_8601}\n";
$date_from_string_and_format = date_create_from_format(DATE_ATOM, $now_iso_8601);
echo "ISO 8601 formatted string, back to DateTime object:\n";
var_dump($date_from_string_and_format);

Drucke

Now in ISO 8601 format: 2018-09-05T08:17:35-10:00
ISO 8601 formatted string, back to DateTime object:
object(DateTime)#2 (3) {
  ["date"]=>
  string(26) "2018-09-05 08:17:35.000000"
  ["timezone_type"]=>
  int(1)
  ["timezone"]=>
  string(6) "-10:00"
}

1312830cookie-checkPHP DateTime::createFromFormat analysiert die ISO 8601-Datumszeit nicht

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy