Les petites choses marrantes en PHP: strtotime vs DateTime

Continuons notre série Les petites choses marrantes en PHP, consacrées aux petites choses marrantes en PHP, avec quelques exemples de petites choses marrantes en matière de résolution de date par Datetime et strtotime.

Mais attention, que les choses soient bien claires: il ne s’agit pas de troll! Juste de faire gaffe…

Une date normale

Donc, la documentation de PHP nous indique que Datetime et strtotime interprètent de la même façon les formats de date.

1
echo date_default_timezone_get(); //UTC
1
2
$date = strtotime('1970-01-01 00:00:00');
date('Y-m-d H:i:s', $date); //"1970-01-01 00:00:00"
1
2
$date = new DateTime('1970-01-01 00:00:00');
$date->format('Y-m-d H:i:s'); //"1970-01-01 00:00:00"

Une date vide

Sauf que cela devient marrant si on passe une string vide: DateTime retourne la date et l’heure courante, tandis que strtotime retourne la date du 1er janvier 1970, chère au système UNIX.

1
2
$date = strtotime('');
date('Y-m-d H:i:s', $date); //"1970-01-01 00:00:00"
1
2
$date = new DateTime('');
$date->format('Y-m-d H:i:s'); //"2014-03-10 12:29:58"

Marrant non?

L’an zéro

Sauf que cela devient marrant si on passe l’an zéro comme on la trouve par défaut dans MySQL: strtotime retourne à nouveau la date du 1er janvier 1970, tandis que DateTime ne retrouve plus ses petits.

1
2
$date = strtotime('0000-00-00 00:00:00');
date('Y-m-d H:i:s', $date); //"1970-01-01 00:00:00"
1
2
$date = new DateTime('0000-00-00 00:00:00');
$date->format('Y-m-d H:i:s'); //"-0001-11-30 00:00:00"

Marrant non?

Le bug de 2038

Sauf que cela devient marrant si on passe une date qui dépasse 32 bits, soit le 19 janvier 1938 à 3h, 14 min et 7 sec: si DateTime s’en sort sans problème, strtotime retourne encore et toujours la date du 1er janvier 1970.

1
2
$date = strtotime('2039-01-01 00:00:00');
date('Y-m-d h:i:s', $date); //"1970-01-01 00:00:00"
1
2
$date = new DateTime('2039-01-01 00:00:00');
$date->format('Y-m-d h:i:s'); //"2039-01-01 00:00:00"

Marrant, non?

Timezone

Dernière considération, tous ces tests ont été fait avec un timezone neutre, soit l’UTC.

1
echo date_default_timezone_get(); //UTC

Mais que se passe-t-il si on modifie le timezone?

1
2
date_default_timezone_set('Asia/Tokyo');
echo date_default_timezone_get(); //Asia/Tokyo (soit + 9 heures)

Normalement, le timezone n’a pas d’impact sur le formatage de la date depuis une string, dans la mesure où l’on ne travaille pas avec des timestamp qui, eux, sont absolus et indépendants du fuseau horaire.

1
2
3
4
$date = strtotime('1970-01-01 00:00:00');
//sous le timezone 'Asia/Tokyo', $date vaut -32400 et pas 0
//mais c'est bien minuit qui est affiché
date('Y-m-d H:i:s', $date); //"1970-01-01 00:00:00"

Le 1er janvier 1970 informatique est basé sur l’UTC. Il était donc 9 heures du matin au Japon. Logique.

1
2
$date = 0;
date('Y-m-d H:i:s', $date); //"1970-01-01 09:00:00"

Dès lors, lorsque que strtotime() retourne la date du 1er janvier 1970 par défaut, il faut bien sûr y voir la date UTC, soit le timestamp 0. Le timestamp est ensuite formaté par date() selon le timezone défini, soit avec un décalage de 9 heures pour Tokyo.

1
2
$date = strtotime('');
date('Y-m-d H:i:s', $date); //"1970-01-01 09:00:00"
1
2
$date = strtotime('0000-00-00 00:00:00');
date('Y-m-d H:i:s', $date); //"1970-01-01 09:00:00"
1
2
$date = strtotime('2039-01-01 00:00:00');
date('Y-m-d H:i:s', $date); //"1970-01-01 09:00:00"

C’est donc le seul cas où nous avons un décalage dû au fuseau horaire, bien qu’on ait passé un format de date en string.

Marrant, non?

L’explication

En réalité, c’est date qui retourne la date du 1er janvier 1970. strtotime ne retourne pas 0 par défaut, mais bien false, lequel est casté en 0 par date.

1
2
$date = strtotime('');
var_dump($date); //bool false

Autrement dit, il est facile de filtrer la réponse de strtotime grâce à une comparaison stricte.

1
2
3
4
$date = strtotime('');
if($date===false){
    echo "la date n'a pas été correctement interprétée";
}

DateTime propose une méthode assez semblable qui retourne également false en cas de problème: DateTime::createFromFormat.

Conclusion

En situation extrême, strtotime retourne false, qui peut être interprété comme la date du 1er janvier 1970 par date.

Pour DateTime, la réponse est plus plus variable: c’est souvent mieux, sauf pour l’an zéro, où c’est pire…

Une réflexion au sujet de « Les petites choses marrantes en PHP: strtotime vs DateTime »

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>