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.
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é.
Le but est de “calculer” la saison:
Avec la valeur calculée, je peut ensuite facilement sélectionner la feuille de style adéquate.
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):
à 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.