Arithmétique avec DateTime

Les exemples suivants montrent quelques pièges de l'arithmétique de DateTime en ce qui concerne les transitions DST et les mois ayant un nombre différent de jours.

Exemple #1 DateTime::add/sub ajout d'un interval de temps écoulé.

Ajouter PT24H au dela d'une transition DST semblera ajouter 23/25 heures (pour          la plupart des fuseaux horaires).

<?php
$dt 
= new DateTime("2015-11-01 00:00:00", new DateTimeZone("America/New_York"));
echo 
"Début: "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt->add(new DateInterval("PT3H"));
echo 
"Fin:   "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>

L'exemple ci-dessus va afficher :

Début: 2015-11-01 00:00:00 -04:00
Fin:   2015-11-01 02:00:00 -05:00

Exemple #2 DateTime::modify et strtotime incrémentation ou décrémentation de valeurs individuelles

Ajouter +24 heures au dela d'une transition DST peut ajouter exactement 24 heures comme vu avec la chaîne date/time (sauf si l'heure de début ou de fin est sur un point de transition).

<?php
$dt 
= new DateTime("2015-11-01 00:00:00", new DateTimeZone("America/New_York"));
echo 
"Début: "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt->modify("+24 hours");
echo 
"Fin:   "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>

L'exemple ci-dessus va afficher :

Début: 2015-11-01 00:00:00 -04:00
Fin:   2015-11-02 00:00:00 -05:00

Exemple #3 L'ajout ou la soustraction de dates/heures peut dépasser (en plus ou en moins) des dates

Comme pour 31 Janvier + 1 mois donnera comme résultat 2 Mars (année bisextile) ou 3 Mars (année normale).

<?php
echo "Année Normale:\n"// Février a 28 jours
$dt = new DateTime("2015-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo 
"Début: "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt->modify("+1 month");
echo 
"Fin:   "$dt->format("Y-m-d H:i:s P"), PHP_EOL;

echo 
"Année bisextile:\n"// Février a 29 jours
$dt = new DateTime("2016-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo 
"Début: "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt->modify("+1 month");
echo 
"Fin:   "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>

L'exemple ci-dessus va afficher :

Année Normale:
Début: 2015-01-31 00:00:00 -05:00
Fin:   2015-03-03 00:00:00 -05:00
Année bisextile:
Début: 2016-01-31 00:00:00 -05:00
Fin:   2016-03-02 00:00:00 -05:00

Pour obtenir le dernier du mois prochain (autrement dit pour prevenir le dépassement), le format last day of est disponible depuis PHP 5.3.0.

<?php
echo "Année Normale:\n"// Février a 28 jours
$dt = new DateTime("2015-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo 
"Début: "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt->modify("last day of next month");
echo 
"Fin:   "$dt->format("Y-m-d H:i:s P"), PHP_EOL;

echo 
"Année bisextile:\n"// Février a 29 jours
$dt = new DateTime("2016-01-31 00:00:00", new DateTimeZone("America/New_York"));
echo 
"Début: "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
$dt->modify("last day of next month");
echo 
"Fin:   "$dt->format("Y-m-d H:i:s P"), PHP_EOL;
?>

L'exemple ci-dessus va afficher :

Normal year:
Début: 2015-01-31 00:00:00 -05:00
Fin:   2015-02-28 00:00:00 -05:00
Année bisextile:
Début: 2016-01-31 00:00:00 -05:00
Fin:   2016-02-29 00:00:00 -05:00