Zend_Date

Logo Zend Framework

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.

Opérations sur les dates

Voici quelques exemples de manipulations :

Vérifier qu'une date au format ISO est valide

<?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');
?>

Obtenir le dernier jour du mois

<?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);   
?>

Obtenir le dernier jour du mois dernier

<?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));   
?>

Aller au prochain Dimanche

<?php
$date 
= new Zend_Date();
// Lundi = 1, Dimanche = 7
$date->setWeekday(7); 
?>

Heure d'été

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(0003292009);
// 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));
?>

Nombre de jours entre deux dates

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

Utiliser le cache

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