2010-12-10 20 views
31

code parle d'un million de mots:PHP DateTime :: createFromFormat ne pas analyser le temps de date 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) 

Toute idée de ce qui se passe? Btw, oui, le nouveau DateTime ("2010-12-07T23: 00: 00.000Z") fonctionne correctement. Mais je préfère savoir quelle contribution je reçois.

+3

Vos fractions de secondes ne font pas partie du format. 'DateTime :: ISO8601' est une chaîne avec la valeur' Y-m-d \ TH: i: sO'. – salathe

+4

WikiPedia n'est pas d'accord: Des fractions décimales peuvent également être ajoutées à l'un des trois éléments de temps. Un point décimal, soit une virgule, soit un point (sans aucune préférence comme indiqué plus récemment dans la résolution 10 de la 22e Conférence générale de la CGPM en 2003), est utilisé comme séparateur entre l'élément temps et sa fraction. Une fraction peut seulement être ajoutée à l'élément de temps le plus bas de la représentation. – Jake

+0

'public static DateTime DateTime :: createFromFormat (chaîne $ format, chaîne $ time [, DateTimeZone $ timezone])', peut-être est provoquée par inclusive du fuseau horaire – ajreal

Répondre

32

Il y a un rapport de bogue qui décrit exactement votre problème :)

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

Depuis 07/08/2016, le rapport de bogue a été marqué comme "pas un bug". Vous devez utiliser strtotime ou new DateTime à la place.

Les constantes qui ont été définies s'appliquent à la fois au formatage et à l'analyse de la même manière, ce qui force vos chemins.

+2

En effet décevant. Pourquoi nommer une constante "ISO8601" si elle n'est pas réellement conforme à cette norme. C'est pourquoi je n'aime pas beaucoup PHP. – jlh

+0

Bloody 7 ans plus tard et cela existe encore .... et est même marqué comme pas un bug? 'Si vous voulez accepter différents formats de date/heure ISO-8601'. Différents formats ISO-8601 ?? Pourquoi je déteste php en un mot. –

+0

Sentiment de la douleur aussi –

1

Il est très étrange et décevant que ce bug soit toujours actuel. Voici un bon modèle pour ce jour l'analyse syntaxique avec microsecondes en partie décimale de secondes:

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

Utilisation:

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

En fait, ce travail seulement si la partie décimale des secondes est présente. De plus, cela ne fonctionne que s'il y a seulement 1 à 6 chiffres de précision. Si la partie décimale est omise ou si elle est plus précise, false est renvoyé. – Glutexo

6

essayez ceci:

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

Parsing Date ISO8601, ainsi que la commutation fuseau horaire:

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

a copié votre code et il imprime: "2016-07-27T19: 30: 00 + 0000" en utilisant PHP 5.6.10 –

+0

@AlexAngelico Quelle est la sortie de 'echo DateTime :: ISO8601;'? Il imprime 'Y-m-d \ TH: i: sO' pour moi. – a20

+0

oui, DateTime :: ISO8601 imprime Y-m-d \ TH: i: sO J'utilise ce code pour changer l'heure au fuseau horaire correct. Je suis dans GMT-5 '$ fecha_str = '2017-04-12T21: 43: 54 + 02: 00'; \t $ date = strtotime ($ fecha_str); \t date d'écho ("Y-m-d h: i: s", $ date); \t/output => 2017-04-12 07:43:54 ' –

2

Personne mentionné à utiliser DATE_ATOM qui est autant que je sache phps la mise en œuvre la plus correcte de la norme ISO 8601. Il devrait au moins travailler pour la dernière de ces trois:

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

?> 

Pour pouvoir analyser tous les i a écrit une petite fonction:

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

?> 

Comme mentionné @Glutexo il ne fonctionne que s'il n'y a que 1 à 6 chiffres de précision pour la partie décimale, aussi. N'hésitez pas à l'améliorer.

0

Pour la réponse listée ici https://stackoverflow.com/a/14849503/2425651 nous pouvons utiliser ce format "Y-m-d \ TH: i: s.u +" pour garder les microsecondes.

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

Celui-ci fonctionne pour moi:

$date = (new DateTime)->setTimestamp(strtotime('2017-12-31T23:00:00.000Z'));