[[fr:leroutier:saisons_devinfo]]
 

"Et ça change de saison tout seul ?"

Ah, c'est le n° 1 du TOP 10 des questions qu'on me pose sur ce nouveau site devinfo.net. C'est pas que ce soit un sujet passionnant en soi, mais c'est de toute évidence une des premières questions qui vient à l'esprit de ceux qui contemplent ce site à côté de moi…

Aujourd'hui, je vais donc vous expliquer, code php à l'appui, comment ça marche. C'est plutôt le genre de sujet passe-partout qu'abordent les gens de ma caste, les développeurs, autour d'un café au bistrot. Rassurez-vous, ça sera plutôt bref, et au cas où votre curiosité a été piquée comme celle de ceux qui m'ont posé la question, c'est toujours sympa de jeter un rapide coup d'oeil au pourquoi du comment.

Respecter le choix du visiteur

Avant d'expliquer les quelques lignes de code, juste un petit mot sur les cas dans lesquels ça ne marche pas (ouais, pas à cause d'un bogue, mais par choix).

A propos des différentes “vues” saisonnières que je vous propose (grâce à l'inventivité, au talent créatif, à l'humour savamment dosé et à l'incroyable habilité graphique de Robert, http://www.i-media.ch), vous pouvez remarquer que vous pouvez “changer de saison” à tout instant grâce aux quatre liens en haut de chaque page (ou presque) du site.

Une fois que vous avez changé de saison, celle que vous avez choisie reste active pendant toute votre session de visite, même si vous surfez le 20 septembre à minuit et qu'à minuit une on change de saison (pour passer d'été en automne). En d'autres termes, si vous sélectionnez une saison par l'un des quatre liens (printemps, été, automne, hiver), le système de détection automatique de changement de saison s'arrête afin de respecter votre préférence de session; vous devrez refermer toutes vos fenêtres de navigateur puis en rouvrir une et surfer à nouveau sur devinfo.net pour voir en le thème associé à la saison automatiquement appliqué.

Calcul de la saison

Le but est de “calculer” la saison:

  • printemps = 1
  • été = 2
  • automne = 3
  • hiver = 4

Avec la valeur calculée, je peut ensuite facilement sélectionner la feuille de style adéquate.

Quand commence et finit une saison ?

La réponse est bien plus compliquée que la solution présentée. J'ai simplifié en considérant que les quatres dates suivantes sont les jours de passage d'une saison à l'autre (en réalité, ces jours “pivot” peuvent varier d'une année à l'autre d'un jour):

  • 21 mars: commence le printemps
  • 22 juin: commence l'été
  • 23 septembre: commence l'automne
  • 21 décembre: commence l'hiver

Calcul

à partir de là, c'est facile: on divise le mois en cours par 3 (division entière) et on obtient donc un entier dans l'intervalle [0..3]. Petit problème, je veux obtenir un entier [1..4] (hiver = 4). J'ai donc simplement créé un tableau de 4 cellules qui contient les chiffres 4,1,2,3.

Euh, pourquoi 4,1,2,3 et pas 1,2,3,4 ? - parcequ'en janvier, c'est l'hiver (n°4)… Pour la suite de la solution, on considère le modulo 3 du n° mois. On griffonne un joli tableau sur un papier:

(rappel: printemps = 1, été = 2, automne = 3, hiver = 4)

Mois Modulo 3 DIV 3 Saison Changement saison
1 1 0 4
2 2 0 4
3 0 1 4 ou 1 21.03
4 1 1 1
5 2 1 1
6 0 2 1 ou 2 22.06
7 1 2 2
8 2 2 2
9 0 3 2 ou 3 23.09
10 1 3 3
11 2 3 3
12 0 4 3 ou 4 21.12

Donc, on voit se profiler une bonne fonction de hash-codage (en pseudo code):

index_saison(mois, jour) retourne: 1,2,3 ou 4 /* printemps = 1, été = 2, automne = 3, hiver = 4 */
{
   tableau = [4, 1, 2, 3]  /* cf colonne "saison" du tableau */
   div3 = mois DIV 3
   mois modulo 3 = 0 ?
     oui
       jour_pivot = [21,22,23,21] /* le jour où la saison change pour chaque saison (de tableau[]) */
       jour < jour_pivot[div3] ?
         oui
           tableau[div3] > 1 ?
           oui
             résultat = tableau[mois DIV 3]-1
           non
             résultat = 4
         non
           résultat = tableau[div3]
     non
       résultat = tableau[div3] /* facile */
}

J'ai utilisé la fonction int_divide() présentée dans un des commentaires du site http://www.php.net (sais plus où).

function int_divide($x, $y)
{
    if ($x == 0) return 0;
    if ($y == 0) return FALSE;
    return ($x - ($x % $y)) / $y;
}
 
/* calcul saison */
$today = getdate();
$iDay   = $today['mday'];
$iMonth = $today['mon'];
$aiSeasonIdx = array(4,1,2,3);
$i = int_divide($iMonth, 3);
$iCalcSeason = $aiSeasonIdx[$i];
if( ($iMonth % 3) == 0 )
{
	$aiPivot = array(21, 22, 23, 21);
	if($iDay < $aiPivot[$iCalcSeason])
	{
		if( $iCalcSeason>1 )
			$iCalcSeason--;
		else
			$iCalcSeason = 4;
	}
}

Le résultat est bien entendu dans la variable $iCalcSeason.

Y a certainement une expression tenant sur une ligne qui peut remplacer ce code, mais pour l'esprit de lisibilité, je préfère être aussi loquace.

CQFD.

fr/leroutier/saisons_devinfo.txt · Dernière modification: 2007/09/18 08:23 (édition externe)
 


© 2007, Développement Informatique Services, tous droits réservés.