Manipulation des dates et heures en PHP5 avec la classe native DateTime

Suite à l'article sur la manipulation des dates en sql, je me suis rendu compte, qu'en fait, la manipulation de date en php n'était pas si simple et connu que ça. Il existe beaucoup de fonctions sur les dates en php et je trouve encore pas mal de code récent qui s'embrouille à essayer de calculer des dates avec des mktime, en manipulant des timestamp....
Alors qu'une class bien pratique existe: DateTime.
C'est donc elle, et ses comparses (DateInterval et DatePeriod), que je vais présenter.

 

Initialisation d'une date

Pour commencer toute manipulation, il faut une date. Rien de plus simple, il suffit d'instancier la class DateTime pour avoir la date actuelle!

$date = new DateTime();

Attention tout de même, si aucune time zone n'est indiquée dans votre fichier php.ini, vous aurez une erreur. Dans ce cas il faudra la préciser à la volée:

$date = new DateTime(null, new DateTimeZone('Europe/Paris'));

Pour une date précise, il suffit de mettre une string à la place de null, plusieurs formats sont autorisés. Mais, par exemple, la valeur saisie dans un champ datetime d'une base de donnée sql fonctionne très bien!

$date = new DateTime('2012-09-01 12:00:00");

On peut aussi spécifier une date relative au moment présent:

$date = new DateTime("+ 2 days");
$date = new DateTime('next sunday");
 

Extraction d'une date

Il est possible d'extraire chaque partie des dates, sous quasiment tous les formats imaginables.
Voici quelques exemples:

$date = new DateTime('2012-09-01 09:00:00', new DateTimeZone('Europe/Paris'));
echo $date->format('m-d-Y'); //01-09-2012
echo $date->format('g\hi'); //9h00
echo $date->format('F, \t\h\e jS'); //September, the 1st
echo $dateformat('\i\t \i\s \t\h\e NS \d\a\y \o\f \t\h\e \w\e\e\k.'); //it is the 6st day of the week.

 

Manipulation de date

Pour modifier une date, plusieurs possibilités s'offrent à nous.
On peut directement modifier notre objet DateTime:

$date = new DateTime('2012-09-01 09:00:00', new DateTimeZone('Europe/Paris'));
$date->modify("+ 2 days");
echo $date->format('m-d'); //03-09

Mais pour être plus précis (et plus typé objet), on peut utilisé la class DateInterval. Pour l'initaliser, le plus propre est de lui passé une durée au format ISO8601.
Puis on ajoute ou soustraire cet intervalle à notre date.

$date = new DateTime('2012-09-01 09:00:00', new DateTimeZone('Europe/Paris'));
$interval = new DateInterval('P10D'); //10 jours
 
$date2 = clone $date;
$date2->add($interval);
echo $date2->format('Y-m-d'); //2012-09-11
 
$date3 = clone $date;
$date3->sub($interval);
echo $date3->format('Y-m-d'); //2012-08-22

La class DateInterval sert aussi dans la comparaison de date.
Pour commencer, on peux très bien écrire:

var_dump($date2 > $date3) //true

Et la fonction diff de la class DateTime nous renverra la différence entre les 2 dates sous la forme d'un intervalle, qui lui même peut s'extraire dans différents formats.

$diff =  $date2->diff($date3);
echo $diff->format('%R%d jours'); //+20 jours

 Attention, ces fonctions modifient l'objet courant. C'est pour cela que je fais des clones. Si vous souhaitez que votre date soit inchangeable, vous pouvez utiliser DateTimeImmutable (disponible depuis 5.5) qui renvoit un nouvel objet. Pour que votre code accepte les deux types de dates (DateTime et DateTimeImmutable), vous pouvez utiliser l'interface commune, DateTimeInterface.

Liste de dates

Disons que nous sommes le 1er septembre, et que nous voulons lister tous les lundis à partir d'aujourd'hui et jusqu'à la fin du mois.

$begin = new DateTime('2012-09-01 09:00:00', new DateTimeZone('Europe/Paris')); //j'initialise ainsi car je ne suis pas le 1/09
$begin->modify('next monday');  
$interval = new DateInterval('P1W'); //interval d'une semaine
$end = clone $begin;
$end->modify('last day of this month'); //dernier jour du mois
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $date) {
   echo $date->format('l, F \t\h\e jS');
}
// Monday, September the 10st
// Monday, September the 17st
// Monday, September the 24st

Ce n'est pas ce que je souhaitais, car je voulais aussi avoir le premier lundi du mois. Hors on considère la première date de la période après une première application de l'intervalle (me suis souvenue de cela en écrivant et testant l'article).
Je peux soit commencer ma prériode au lundi précédant:

$begin = new DateTime('2012-09-01 09:00:00', new DateTimeZone('Europe/Paris'));
$begin->modify('last monday');
$interval = new DateInterval('P1W');
$end = clone $begin;
$end->modify('last day of next month');
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $date) {
   echo $date->format('l, F \t\h\e jS');
}
// Monday, September the 3rd
// Monday, September the 10st
// Monday, September the 17st
// Monday, September the 24st

Soit modifier mon interval en lui indiquant de prendre le lundi suivant, mais dans ce cas il faut l'instancier à partir d'une chaîne de caractères.

$begin = new DateTime('2012-09-01 09:00:00', new DateTimeZone('Europe/Paris'));
$interval = DateInterval::createFromDateString('next monday');
$end = clone $begin;
$end->modify('last day of this month');
$period = new DatePeriod($begin, $interval, $end);
foreach ($period as $date) {
   echo $date->format('l, F \t\h\e jS');
}
// Monday, September the 3rd
// Monday, September the 10st
// Monday, September the 17st
// Monday, September the 24st

 

Voilà, j'espère que cet article vous a plu et vous a donné envie de jouer avec ces classes si vous ne les connaissiez pas!

Il y a un commentaire.

Ecrit par Sébastien Julien (Canada) le 31 déc. 2013

WOW super. J'adore J'adore j'adore. Car je me suis pris la tête pour pour voir boucler vers l'arrière de 4 semaines depuis la date en cours et boucler en avant de 4 semaines. Ouf, Merveilleux. Pour ce faire je dis : start = first monday of -1 month et end = last day of +2 month Super. Je liste alors uniquement les dates de lundi comprises entre ces deux dates. MERVEILLEUX. J'en veux encore.

Ajouter un commentaire