Zend_Date est un des principaux composants du Zend Framework. Il présente de nombreux avantages par rapport aux fonctions natives de PHP, mais son utilisation n'est pas toujours intuitive.
Prenons la méthode getMonth. A votre avis qu'est-ce que cette méthode retourne pour une date située au mois d'Avril ?
La première réponse qui vient à l'esprit, c'est le chiffre 4 qui correspond au numéro du mois. Mais en fait c'est un nouvel objet initialisé au 1er avril 1970 qui est retourné.
Pour obtenir le numéro du mois, il faut utiliser la méthode get avec la constante appropriée :
<?php
// Affiche le numéro du mois en cours
$date = new Zend_Date();
echo $date->get(Zend_Date::MONTH);
?>
Il faut bien aussi avoir en tête que les différentes opérations (add, sub...) affectent l'objet sur lequel elles sont appliquées. Pour obtenir un nouvel objet date à partir d'un objet existant, il faut le cloner à l'aide du mot clé clone.
Voici quelques exemples de manipulations :
<?php
// Affiche 'Date valide'
$validDate = '2008-01-01';
echo 'Date ' . (Zend_Date::isDate($validDate, 'YYYY-MM-dd') ? 'valide' : 'invalide');
// Affiche 'Date invalide'
$invalidDate = '2008-02-31';
echo 'Date ' . (Zend_Date::isDate($invalidDate , 'YYYY-MM-dd') ? 'valide' : 'invalide');
// Affiche 'Date invalide'
$invalidDate = 'abc';
echo 'Date ' . (Zend_Date::isDate($invalidDate , 'YYYY-MM-dd') ? 'valide' : 'invalide');
?>
<?php
$date = new Zend_Date();
// On ajoute un mois pour aller au mois suivant
$date->addMonth(1);
// On revient au 1er jour du mois suivant
$date->setDay(1);
// On enlève une journée pour revenir au dernier jour du mois en cours
$date->subDay(1);
?>
<?php
$date = new Zend_Date();
// On retire un mois pour aller au mois précédent
$date->subMonth(1);
// On règle la date au dernier jour du mois qu'on obtient avec la constante MONTH_DAYS
$date->setDay($date->get(Zend_Date::MONTH_DAYS));
?>
<?php
$date = new Zend_Date();
// Lundi = 1, Dimanche = 7
$date->setWeekday(7);
?>
Le passage à l'heure d'été peut entrainer des problèmes lorsqu'on effectue des calculs de date.
Par exemple, pour l'année 2009, le passage à l'heure d'été s'est effectué le 29 mars à 2 heures du matin. Si on effectue des calculs sur des dates qui sont à cheval, on risque d'avoir un résultat inattendu :
<?php
// Note : le fuseau horaire est réglé à Europe/Paris
// Crée une date correspondant au 29 mars 2009 à minuit
$date1 = mktime(0, 0, 0, 3, 29, 2009);
// Affiche 29/03/2009 00:00
echo date('d/m/Y H:i', $date1);
// Ajoute une journée (86 400 secondes)
$date2 = $date1 + 86400;
// Affiche 30/03/2009 01:00
echo '<br>' . date('d/m/Y H:i', $date2);
?>
L'heure qui était réglée sur minuit se retrouve à 1:00 du matin. Avec Zend_Date :
<?php
Zend_Date::setOptions(array('format_type' => 'php'));
// Crée une date correspondant au 29 mars 2009 à minuit
$date1 = new Zend_Date(
array(
'year' => 2009,
'month' => 3,
'day' => 29
)
);
// Affiche 29/03/2009 00:00
echo $date1->toString('d/m/Y H:i');
$date2 = clone $date1;
$date2->addDay(1);
// Affiche 30/03/2009 00:00
echo '<br>' . $date2->toString('d/m/Y H:i');
?>
Une heure est ajoutée ou soustraite automatiquement . Vous pouvez désactiver ce comportement en mettant à false l'option fix_dst.
<?php
Zend_Date::setOptions(array('fix_dst' => false));
?>
Si vous voulez calculer le nombre de jours ou d'heures séparant deux dates, Zend_Date ne propose pas encore de méthode pour le faire.
On peut utiliser la méthode getTimestamp pour récupérer une valeur exprimée en secondes qu'on peut ensuite convertir en minutes, heures ou journées à l'aide d'une simple division.
Attention cependant à l'heure d'été : si c'est le nombre de jours qu'il vous faut, un round sur le résultat fera l'affaire, puisque l'erreur portera sur une heure au maximum, soit 1/24.
<?php
// Nombre de jours entre deux dates (situées à la même heure)
$count = round(($date2->getTimestamp() - $date1->getTimestamp()) / 86400);
?>
Si vous voulez le nombre d'heures, de minutes ou de secondes il faut passer dans le fuseau horaire UTC qui n'est pas affecté par l'heure d'été.
<?php
// On modifie le fuseau horaire par défaut de PHP pour créer des dates dans le fuseau
// horaire UTC
$timezone = date_default_timezone_get();
date_default_timezone_set('UTC');
$date1 = new Zend_Date(
array(
'year' => 2009,
'month' => 3,
'day' => 29
)
);
$date2 = new Zend_Date(
array(
'year' => 2009,
'month' => 3,
'day' => 30
)
);
date_default_timezone_set($timezone);
// Affiche 24
echo (($date2->getTimestamp() - $date1->getTimestamp()) / 3600);
?>
N'oubliez pas de restaurer le fuseau horaire par défaut, car il affecte toutes les fonctions de date de PHP.
On peut également étendre Zend_Date :
<?php
class Wiip_Date extends Zend_Date
{
public function getDifference(Zend_Date $date, $part = Zend_Date::SECOND)
{
$dividers = array(
Zend_Date::SECOND => 1,
Zend_Date::MINUTE => 60,
Zend_Date::HOUR => 3600,
Zend_Date::DAY => 86400
);
if (!isset($dividers[$part])) {
throw new Zend_Date_Exception('Bad part value');
}
$diff = $this->getTimestamp() - $date->getTimestamp();
// $_options est une propriété privée de Zend_Date, on ne peut pas
// y accèder depuis une classe dérivée
// if (self::$_options['fix_dst']) {
$diff += ($this->get(Zend_Date::DAYLIGHT) - $date->get(Zend_Date::DAYLIGHT)) * 3600;
// }
return $diff / $dividers[$part];
}
}
?>
Le composant réalise des calculs assez complexes en utilisant l'extension bcmath pour manipuler des nombres de grande taille. Il fournit aussi des versions localisés des dates. Toutes ces fonctionnalités ont un impact sur ses performances. Vous pouvez limiter la casse en activant le cache dans votre bootstrap.
<?php
// Mise en place d'un cache utilisant APC
$memCache = Zend_Cache::factory(
'Core',
'APC',
array(
'automatic_serialization' => true,
'lifetime' => 86400 // 24h
)
);
// Demande à Zend_Date d'utiliser le cache
Zend_Date::setOptions(array('cache' => $memCache ));
?>
Ajouter un commentaire