Index de l'article

Calculs sur des champs date

Extraire une partie d'une date

Bien pratique pour faire des regroupements dynamiques sur les mois par exemple, dans un calendrier ou une application de réservation.

Utilisez les constantes de date PHP, ici F (mois textuel complet) et Y (année complète en chiifre). Ici nous les séparons par une virgule, et les stockons dans une variable nommée $FullMonthAndYear.

Dans un champ calc :

$FullMonthAndYear = '{table___date_field_raw}' ;
 
$FullMonthAndYear = date("F, Y", strtotime($FullMonthAndYear)) ;
 
return $FullMonthAndYear ;

Filtrer une liste sur la date actuelle

Dans un Pre-filter classique :

DATE(NOW())

Comparer une date avec une autre

Pour vérifier qu'une date saisie est bien supérieure/inférieure/égale à une autre. Dans le cas de systèmes de réservation par exemple, vous aurez sans doute par la suite des process nécessitant des champs dates correctement saisis (créer un calendrier, chercher les overlaps...).

Dans le code ci-dessous, les dates sont formatées en AnnéeMoisJour (ex : 20161208), nous ne comparons donc ici que les jours, un jour de fin devant être supérieur au jour de début par exemple.

Dans une règle de validation PHP (sur un élément), ajoutez simplement ce type de code, qui doit retourner true pour valider le formulaire :

// date 1
$startDate = $formModel->formData['ma_table___date_1'];
$startDate = new DateTime($startDate);
$startDate = $startDate->format('Ymd');
 
// date 2
$endDate = $formModel->formData['ma_table___date_2'];
$endDate = new DateTime($endDate);
$endDate = $endDate->format('Ymd');
 
//var_dump ($startDate,$endDate) ;
 
return $endDate > $startDate ;

Compter les nuits entre 2 champs date

Bien pratique pour un système de réservation de chambres par exemple. Dans un champ calc (de type text) :

// Suppression des avertissements PHP en cas d'absence de timezone dans le INI
if( ! ini_get('date.timezone') )
{date_default_timezone_set('GMT');}
 
// Déclaration du champ date de début et vidange du settime
$datetime1 = new DateTime('{ma_table___mon_champ_date1}');
$datetime1->setTime(0,0,0);
 
// Déclaration du champ date de fin et vidange du settime
$datetime2 = new DateTime('{ma_table___mon_champ_date2}');
$datetime2->setTime(0,0,0);
 
// Calcul de l'intervalle via la fonction diff, et formattage en jours (%a), équivalent en nuits puisque simple intervalle
$interval = $datetime1->diff($datetime2);
 
return $interval->format('%a');

Retrancher automatiquement un jour

Parfois vous avez besoin de retrancher un jour du jour de fin d'un événement. Dans le cas de réservations de chambres d'hôtel par exemple, les nuits vont être réservées mais les jours de départ d'un client doivent être affichés comme disponibles (cela rendra un calendrier mensuel plus lisible, en ne comptabilisant pas les jours de départ).

Ce code fonctionne dans un champ calc (de type text), qui va reprendre le champ datetime à retrancher :

$MaDateOriginale = new DateTime('{ma_table___mon_champ_date}');
return $MaDateOriginale->modify('-1 day')->format('Y-m-d H:i:s');

Trouver des chevauchements de périodes

Pour divers systèmes de réservation, on souhaite trouver des chevauchements (overlap) de périodes entre 2 champs dates pour un même objet. Au moment de saisir une réservation typiquement, pour vérifier que l'objet concerné n'est pas déjà booké.

Le code suivant commence par récupérer 4 variables du formulaire courant :

  1. l'id de la réservation (nous avons donc une table des réservations)
  2. l'id de l'objet (un outil, une chambre... les objets ont leur propre table, dont nous récupérons l'id dans la table des réservations)
  3. la date de début de la réservation
  4. la date de fin de la réservation

La requête cherche ensuite les réservations existantes dont les dates de début sont inférieures à la date de fin saisie et dont les dates de fin sont supérieures à la date de début saisie, cela uniquement pour un objet (inclusion dans la requête de l'id de l'objet) et sans compter la réservation courante (exclusion de l'id de la réservation).

Remarquez également dans le code, la dernière condition de la requête, qui ne s'exécute que si la variable n'est pas vide. Ceci afin de ne pas faire échouer la requête dans certains cas (mais aucune différence ici). Defensive coding dirait Cheesegrits (Fabrik).

Les variables en question sont ici dans un sous-formulaire répétable, donc dans un tableau (array). Si ce n'est pas votre cas, vous n'avez qu'à supprimer les [$repeatCounter] ainsi que les lignes contenant is_array.

Cela dans une règle de validation PHP d'un élément (celui de l'objet de la réservation idéalement), qui va retourner true si aucun overlap n'est trouvé, sinon false, qui fera échouer la validation du formulaire.

// Get the booking_room id, might be an array - Useful to exclude the current record of the request, in order to authorize the modification of this record
$myBookingRoomId = $formModel->formData['table_reservation___id'][$repeatCounter];
$myBookingRoomId = is_array($myBookingRoomId) ? $myBookingRoomId[0] : $myBookingRoomId;
 
// Get the room id from the booking_room table, might be an array
$myRoomId = $formModel->formData['table_reservation___room_raw'][$repeatCounter];
$myRoomId = is_array($myRoomId) ? $myRoomId[0] : $myRoomId;
 
// Date 1, might be an array
$startDate = $formModel->formData['table_reservation___date_1'][$repeatCounter];
$startDate = is_array($startDate) ? $startDate[0] : $startDate;
$startDate = new DateTime($startDate);
$startDate = $startDate->format('Ymd');
 
// Date 2, might be an array
$endDate = $formModel->formData['table_reservation___date_2'][$repeatCounter];
$endDate = is_array($endDate) ? $endDate[0] : $endDate;
$endDate = new DateTime($endDate);
$endDate = $endDate->format('Ymd');
 
//var_dump($endDate);
 
// Now do the query ...
$myDb = FabrikWorker::getDbo();
$myQuery = $myDb->getQuery(true);
 
$myQuery
->select('*')
->from('app_booking_rooms')
->where("DATE_FORMAT(table_reservation.date_1, '%Y%m%d') <= '$endDate' -1")
->where("DATE_FORMAT(table_reservation.date_2, '%Y%m%d') -1 >= '$startDate'")
->where("table_reservation.room = '$myRoomId'");
 
if (!empty($myBookingRoomId)) {
$myQuery->where("table_reservation.id <> '$myBookingRoomId'");
}
 
// Uncomment this to test, make sure the query is sane
 
//var_dump((string) $myQuery);
 
//var_dump ($startDate,$endDate) ;
 
$myDb->setQuery($myQuery);
$myResults = $myDb->loadObjectList();
 
// Return false if we found any rows
return empty($myResults);

Ce code fomate les dates pour récupérer une concaténation numérique de l'année complète, du mois et du jour (ex : 20161208).

Cela facilite les comparaisons numériques et permet si besoin de faire des opérations sur ces valeurs (nous retranchons ici un jour des dates de fin, le -1 dans la requête).

Modifiez le code si vous souhaitez utiliser les horaires complètes, mais attention aux fuseaux horaires, je crois que dans ce cas une conversion en GMT sera préférable (CONVERT_TZ).

Liens ou pièces jointes
Accéder à cette adresse URL (http://fabrikar.com/forums/index.php?wiki/troubleshooting-tools/)Wiki Fabrik sur les troubleshooting tools[Article]0 Ko
Accéder à cette adresse URL (http://fabrikar.com/forums/index.php?wiki/calculation-element/)Wiki Fabrik sur les champs calc pour débogage[Article]0 Ko
Accéder à cette adresse URL (http://fabrikar.com/forums/index.php?wiki/php-form-plugin/)Wiki Fabrik sur le plugin PHP pour les formulaires[Article]0 Ko
Accéder à cette adresse URL (http://fabrikar.com/forums/index.php?wiki/filtering-lists-tables/)Filtres de listes[Article officiel Fabrik sur les pré-filtres de listes]0 Ko
Accéder à cette adresse URL (https://api.joomla.org/cms-3/classes/JDatabaseDriver.html)Joomla! API[Documentation Joomla]0 Ko
Accéder à cette adresse URL (https://docs.joomla.org/Selecting_data_using_JDatabase)Selecting data using JDatabase[Documentation Joomla]0 Ko