35.4 exemple calendrier : objet date |
See You Why? |
Trois nouveaux exemples développés dans la séquence précédente... attaquons ce dernier qui, malgré sa simplicité apparente, est plus sérieux qu'il n'apparait...
Nous ne créerons ici qu'un affichage du calendrier du mois en cours (par défaut) et ajouterons la possibilité de sélectionner un autre mois. Dans les exemples multiples de JS, nous développerons cette idée de base (voir "Calendrier perpétuel et options diverses").
Notre calendrier actuel est le calendrier grégorien (du nom du pape Grégoire XIII) qui a succédé au calendrier julien (du nom de Jules César) et le calendrier julien remplaça l'ancien calendrier républicain romain.
Un bref rappel historique ne nous fera pas de tort pour comprendre certaines procédures que nous employerons plus loin. Chacun sait que le temps se mesure en jours (répétition du cycle jour/nuit), en années (répétition du cycle des positions du soleil dans le ciel), en saisons (cycle des nuits les plus longues, les plus courtes et égalité des longueurs jour/nuit) et en mois pour diviser une année trop longue en essayant de tenir compte du cycle d'apparition et positionnement de la lune (cycle de 29,5 jours environ), mais il était bien difficile d'accorder ces mesures qui n'ont que peu de liens entre elles.
Le mot "calendrier" trouverait son origine du latin : les calendes étaient le premier jour de chaque mois, le jour de la Nouvelle Lune. Déjà avant Jules César, on travaillait avec un calendrier lunaire (12 mois alternativement de 29 et 30 jours, ce qui faisait une moyenne de 354 jours par an) et on avait remarqué qu'une année tropique dite normale comptait un peu plus que 365 jours, doù les festivités des calendes de mars, jours de fête ajoutés pour attendre la prochaine nouvelle lune.
Aujourd'hui encore, le calendrier musulman et le calendrier hébreu suivent cette division. À partir de cette division en mois lunaires (ou synodiques [à essayer de placer dans une conversation]), chacun y est allé de sa méthode pour aligner ses observations.
Le calendrier romain supprimait ces calendes aléatoires et supprimait aussi les 4 ou 5 derniers jours de l'année (le douzième et dernier mois qui s'appelait Februarius) et les remplaçait par un mois intercalaire tous les deux ans... L'année commençait toujours aux ides de mars (appelé Primus à l'époque, à la nouvelle lune du début du printemps, date variable selon les années) et se terminait donc en février, mois martyr des calendriers (après Iunius, les mois s'appelaient respectivement Quintilis, Sextilis, September, October, November, December qui étaient les 5e à 10e mois de l'année). Logiques, ces Romains...
Ce calendrier avait de gros inconvénients :
* une année pouvait compter de 354 jours à 377 ou 378 jours, selon le nombre de jours supprimés pour le remplacer par le mois intercalaire de 27 jours ;
* calculée sur une très longue durée, la longueur d'une année moyenne 366,25 jours (un peu de trop pour s'harmoniser avec ce que l'on appelle aujourd'hui une année tropique (intervalle de temps, sur Terre, pour que le Soleil retourne à la même position dans le cycle des saisons) ;
* chaque année ne compte pas le même nombre de mois.
Pour rapprocher rapprocher ce calendrier républicain romain de l'année tropique, plusieurs méthodes ont été successivement adoptées...
* garder l'ancienne division de l'année et y incorporer occasionnellement une "semaine commerçante" ;
* fixer un cycle d'apparition de 3 années intercalaires sur une périodes de 24 années ;
Finalement, c'est en -46 que Jules César introduisit le système d'années de 365 jours et un jour supplémentaire tous les quatre ans et fixa une alternance de durée des mois de 30 et 31 jours sauf février (le dernier mois de l'année) qui a toujours été le mois "sacrifié". Ce fut l'abandon des mois lunaires. Évidemment, en son honneur, Jules fit rebaptiser le mois Quintilis (son anniversaire) en Julius.
Depuis César, de nombreuses autres petites modifications ont eu lieu, mais toutes ont gardé le principe d'une année moyenne de 365,25 jours par an.
Ne citons que celle d'Auguste, successeur de Jules César... d'où les mois consécutifs de Julius (pour juillet) et Augustus pour aout (plus d'accent obligatoire depuis 1990, voir 'orthographe 1990'). Auguste ne pouvait supporter que César ait un mois qui lui soit attribué (Julius) et que lui n'en n'ait pas ; il décida donc de renommer le mois suivant, initialement Sextilis (6e, avant September) et le mois Augustus était né... mais quoi de plus insupportable que Augustus ne compte que 30 jours, alors que Julius en comptait 31 (respect de l'alternance initiale)... et voilà notre calendrier bouleversé et un jour de plus sur l'année (décembre en compte maintenant 31, pour 30 dans la version Jules César... peu importe, février en souffrira et de 29 jours dans la version de Jules, il n'en comptera plus que 28 après Auguste.
Nous ne ferons pas état de chaque modification, mais le début de l'année est fixée au 1er janvier (le 1er jour du 11e mois) depuis -153 (date d'élection des consuls romains, même si la durée des mandats variait de 354 à 378 jours), et la moyenne des années restait à 365,25 jours alors que les mesures de l'année tropique se précisaient... l'année tropique (basée sur la rotation de la terre autour du soleil dont on ignorait l'existence, mais on repérait la même position du soleil dans le ciel) est d'une longueur moyenne de 365,2421935 jours (basés actuellement sur la durée de rotation de la terre sur elle-même).
Quelques remarques importantes devraient nous permettre de mieux "philosopher scientifiquement". Jésus-Christ n'est pas né en l'an 'zéro'.
* Les Romains ne connaissaient pas le 'zéro', l'année qui a précédé l'an 1 était donc l'an -1.
* En -46, Jules César ne pouvait pas savoir que 46 ans plus tard Jésus naitrait.
* Si c'était vrai, Noël ne serait pas le 25 décembre, mais le premier de l'an.
* Les romains dataient généralement tous les évènements à partir de la fondation de Rome, anno urbis 1 (754 avant notre ère, généralement notée 754 av.J.C.).
* Au VIe siècle, un moine fixe (avec plusieurs erreurs) la naissance de Jésus au 25 décembre de l'anno urbis 754 (c'est-à-dire 754 ans après la fondation de Rome)... quelle coïncidence.
* Il est historiquement prouvé que Hérode Ier le Grand est né à Ascalon en 73 av. J.-C. et mort à Jéricho en 4 av. J.-C (750 anno urbis). Il est roi de Judée de 37 av. J.-C. à sa mort en 4 av. J.-C. Or, selon l'évangile de St Matthieu, c'est lui qui ordonna de tuer les saints innocents dans le but de faire disparaitre le futur roi des juifs... qui allait naitre 4 ans plus tard ???
* Plusieurs historiens éclairés situent la naissance du personnage de Jésus (dont personne ne rejettent l'existence) entre les années -2 et -7 (aussi notées 2 av.J.C. ou 7 av.J.C.). Le jour et le mois de cette naissance restent cependant inconnus. Cependant, des textes bibliques (Luc I,26) situent l'Annociation (célébrée le 25 mars) neuf mois avant la Noël... mais les mois n'avaient pas la même durée à l'époque romaine qu'aujourd'hui.
* De nombreux historiens et scientifiques s'accordent à prétendre que depuis 153 av.J.C., les années commençaient à l'équinoxe du printemps (date pour laquelle la logueurs du jour égalait la longueur de la nuit, d'où ce nom d'origine latine [(aequus = égal) et (nox = nuit)]. Or l'équinoxe de printemps est actuellement toujours située entre le 20 et le 25 mars... serait-ce le départ d'une nouvelle année romaine ?
* Cette approche, confirmée par le Coran de nos amis musulmans, qui sans donner de précisions de dates, nous parle aussi de cette Anonciation : L'Annonciation dans le Coran explique que l'ange Gabriel (deux anges dans une autre partie du Coran) a annoncé à Marie qu'elle aura Jésus. L'Annonciation est également décrite dans le Coran, dans la sourate 003:045 ( Al-i-Imran - La famille d'Imran ) versets 45-51 ( Yusuf Ali traduction) :
« 45 Voici ! les anges dirent : "O Marie, voilà qu'Allah te donne la bonne nouvelle d'une Parole de Lui : son nom sera Jésus-Christ, le fils de Marie, en l'honneur dans ce monde et l'au-delà et de (l'entreprise de) ceux plus proche de Allah ; " »
Et Sura 019:016 ( Maryam - Marie ) versets 16-26 se réfèrent également à elle. La tradition musulmane veut que l'Annonciation a eu lieu durant le mois de Ramadan".
C'est en 1582 que le pape Grégoire XIII instigua la correction de la dérive séculaire entre l'année julienne et l'année tropique (0,8 jour par siècle, soit environ 13 jours depuis le calendrier julien). Une nouvelle définition de l'année bissextile fut établie en décembre 1582 dans le calendrier grégorien : "Pour assurer un nombre entier de jours à l'année, on y ajoute tous les 4 ans (années dont le millésime est divisible par 4) un jour intercalaire, le 29 février (voir année bissextile), à l'exception des années séculaires qui ne sont bissextiles que si leur millésime est divisible par 400. On considéra donc comme années communes (années de 365 jours) les millésimes qui sont multiples de 100 sans être multiples de 400. Ainsi 1600 et 2000 furent bissextiles, mais pas 1700, 1800, 1900 qui furent communes. De même, 2100, 2200, 2300 seront communes, alors que 2400 sera une année bissextile."
Un rapide calcul nous permettra de calculer la nouvelle durée moyenne d'une année grégorienne :
365 + 1/4 - 1/100 + 1/400,
soit 365,25 - 0,01 +0,0025 ou encore 365,2425.
Applicable à partir de 1582, ce calendrier fut étendu aux années qui précédent 1582, c'est ce qu'on appelle le 'calendrier grégorien proleptique'.
Certes, on n'atteint pas encore la mesure de l'année tropique, mais la dérive n'est plus que de 3 jours en 10 000 ans... quel progrès par rapport au 0,8 jour par siècle.
Évidemment, il serait facile de corriger cette dérive par une nouvelle règle d'exception, mais ce serait oublier que d'une part, la terre accélère quasi insensiblement sa rotation autour du soleil (donc l'année tropique diminue) et que d'autre part, la terre ralentit sa vitesse de rotation sur elle-même (donc les jours allongent).
Vouloir corriger ces variations diverses et non constantes sur des milliers d'années serait vouloir être plus catholique que le pape (sans capitale, car aucun pape en particulier n'est désigné [voir majuscule/minuscule]).
Le lecteur passionné par l'histoire des calendriers est invité à consulter le site de Louis Goguillon "Saga".
Commençons notre script dans le <body> de notre page, en créant quelques tableaux ou arrays (désolé, mais je précise car en français, "tableau" désigne aussi bien les 'arrays' (liste de valeurs - voir 'tableaux en JS') que les 'tables' propres au HTML (tableau de lignes et colonnes - voir 'voir tableaux en HTML')) reprenant les jours, abréviations des jours, mois en français, etc.
var t_ListeJours = new Array("Jour", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim");
var t_ListeMois = new Array("Mois", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");
var t_LongMaxMois = new Array("long.max",31,29,31,30,31,30,31,31,30,31,30,31);
Remarquons que le premier élément de chaque array n'est ni un jour, ni un mois, ni une valeur indiquant le nombre de jours du mois... c'est pour compenser le fait que JS numérote ses arrays à partir de zéro, alors que nous comptons généralement à partir de un.
Relevons ensuite la date actuelle... retour de notre 'nu' néerlandais ;o).
var nu = new Date();
var nuAn = nu.getFullYear();
var nuMois = nu.getMonth() + 1;
var nuDate = nu.getDate();
var nuJour = nu.getDay() + 1;
L'historique ci-dessus nous amène à pouvoir vérifier si une année est bissextile (donc divisible par 4, mais pas par 100 ou divisible par 400), en renvoyant le nombre de jours en février, de la manière suivante :
function fevrierbissextile(annee) {
if ((annee % 100 != 0 && annee % 4 == 0) || (annee % 400 == 0)) {
return 29;
} else {
return 28;
}
}
On affichera la date dans un script JS qui notera par défaut la date actuelle dans un formulaire CalPerpet
avec listes déroulantes... ce qui permettra de choisir d'autres dates. Un rappel HTML : une balise <select> avec autant de balises <option> qu'il n'y a de choix et le paramètre SELECTED pour l'option préchoisie. Quoi de plus rapide qu'une belle boucle FOR pour créer cette liste déroulante des jours (1 à 31 et le jour en cours présélectionné). La procédure sera quasi identique pour les jours, mois, siècles et années. On se souviendra que le calendrier grégorien n'a été mis en vigueur qu'en 1582, donc pas de choix avant cette date.
<form name="CalPerpet"><center>
<br><br><br><h3>CALENDRIER PERPÉTUEL</h3>
<script type="text/javascript">
/* ***********************************************
pour afficher les listes déroulantes et
sélectionner jour, mois, siècle et année
***************jour****************************** */
jourTexte = "<select name='selJour'>"
for (d=1; d<32; d++) {
jourTexte += "<option";
if (d == nuDate) {
jourTexte += " SELECTED";
}
jourTexte += ">";
if (d < 10) {
jourTexte += "0";
}
jourTexte += d + "</option>";
}
jourTexte += "</select>";
/******************mois***************************/
moisTexte = "<select name='selMois'>"
for (m=1; m<13; m++) {
moisTexte += "<option";
if (m == nuMois) {
moisTexte += " SELECTED";
}
moisTexte += ">";
moisTexte += t_ListeMois[m] + "</option>";
}
moisTexte += "</select>";
/*******************siècle************************/
siecleTexte = "<select name='selSiecle'>"
for (c=15; c<25; c++) {
siecleTexte += "<option";
if (c == Math.floor(nuAn / 100)) {
siecleTexte += " SELECTED";
}
siecleTexte += ">" + c + "</option>";
}
siecleTexte += "</select>";
/*********************année**********************/
anneeTexte = "<select name='selAn'>";
for (y=0; y<100; y++) {
anneeTexte += "<option";
if (y == (nuAn - Math.floor(nuAn / 100) * 100)) {
anneeTexte += " SELECTED";
}
anneeTexte += ">";
if (y < 10) {
anneeTexte += "0";
}
anneeTexte += y + "</option>";
}
anneeTexte += "</select>";
/*************************************************/
document.write("date : "+jourTexte + moisTexte + "<br>année : " + siecleTexte + anneeTexte);
</script>
<input type="button" value=" OK " style="font-weight: bold" onClick="VerifDonnees()">
<br><br>
<input type="button" value=" Revenir à la date courante " style="font-weight: bold" onClick="document.CalPerpet.reset();VerifDonnees()">
<br><br><br>
<div id="Calendrier"></div>
</center></form>
<script type="text/javascript">VerifDonnees()</script>
Ce formulaire étant accompli, il nous appartiendra de vérifier les données, raison d'être de la fonction VerifDonnees() prévue ci-dessus, mais qu'il nous reste à définir. En attendant, il serait bon de vérifier si tout cela fonctionne bien (sauf les clics sur les boutons évidemment).
Exemple
|
Normalement la date affichée devrait être correcte, mais comme il sera permis de modifier la date, il serait prudent de vérifier que la date entrée par l'internaute visiteur (ou par tout autre moyen, à l'avenir) soit une date correcte. On prendra alors la précaution de vérifier dans chaque cas.
Nous venons de tester l'affichage correcte de la date dans les listes déroulantes et c'est là aussi que le visiteur de votre page pourrait choisir une autre date... nous récupérerons donc les données souhaitées dans le formulaire CalPerpet
et dans chacun des champs 'selJour
', 'selMois
', 'selSiecle
' et 'selAn
'. Nous n'oublierons pas de corriger la durée du mois de février, le cas échéant.
/* ********** verifier les donnees fournies *********************** */
function VerifDonnees() {
jourSouh = document.CalPerpet.selJour.selectedIndex + 1;
moisSouh = document.CalPerpet.selMois.selectedIndex + 1;
anSouh = (document.CalPerpet.selSiecle.selectedIndex + 15) * 100 + document.CalPerpet.selAn.selectedIndex;
t_LongMaxMois[2] = fevrierbissextile(anSouh);
/* ********** vérifier si date choisie est du calendrier grégorien ************ */
if ((anSouh * 10000 + moisSouh * 100 + jourSouh) < 15821220) {
alert("Date antérieure au 20 décembre 1582, hors du calendrier Grégorien.
\nMerci de choisir une date ultérieure.");
document.CalPerpet.reset();
VerifDonnees();
} else if (MonthLength[QueryMonth] < QueryDate) {
/* *********** verifier si le jour ne dépasse pas la longueur du mois *************** */
alert("Il n'y a pas " + jourSouh + " jours en " + t_ListeMois[moisSouh] + " "
+ anSouh + " mais " + t_LongMaxMois[moisSouh] +
". \nMerci de choisir une autre date.");
document.CalPerpet.reset();
VerifDonnees();
} else {
AfficheCalendrier(); }
}
Les principales vérifications sont faites... nous sommes prêts à afficher le calendrier du mois courant. Le lecteur attentif aura remarqué que les variables employées ne sont pas locales, mais globales, contrairement à ce que nous vous suggérions. La raison en est que ces variables devront être lues et/ou modifiées ailleurs et entre autres dans d'autres fonctions.
Le calendrier sera un tableau à 8 colonnes (les 7 jours de la semaine et une pour marquer le numéro de la semaine). Combien de lignes ? Cela dépendra de la longueur du mois et du jour (lundi à dimanche) du 1er jour du mois.
Encore faut-il connaitre quels sont les numéros des semaines du mois à afficher. Nous admettrons que la semaine 1 est celle qui comprend le premier lundi de l'année.
Toujours est-il que les deux premières lignes de notre tableau seront toujours les mêmes : l'affichage du mois et de l'année souhaités en travers des 8 colonnes, puis en 2e ligne, l'affichage des jours (lundi, mardi...) de la semaine.
Et, comme tout ceci résultera de calcul à effectuer en Javascript, nous stockerons chaque ligne à afficher dans des variables CalLigne que nous numéroterons.
Démarrons :
function AfficheCalendrier() {
//================ligne1 CalendLigne1 = "<table cellspacing=0 cellpadding=3 border=3 bordercolor=#335533>";
jourCle = rechercheJourCle(anSouh,moisSouh,jourSouh); // pour avoir le n° du jour (Lu,Ma...)
ligneRef = defLigne(jourSouh); // la ligne qui contiendra la date choisie
ligneUne = defLigne(1); //la ligne qui contiendra le premier du mois de la date choisie
CalendLigne1 += "<tr align=center><td colspan=8 class=TITRE><b>" + t_ListeMois[moisSouh] + " " + anSouh + "</b></td></tr><tr align=center>";
//================ligne2
CalendLigne2 = "<td><b><font color=#888888>Sem</font></b></td></tr>";
for (s=1; s<8; s++) {
if (jourCle == s) {
CalendLign2 += "<td><b><font color=#ff0000>" + t_ListeJours[s] + "</font></b></td>";
} else {
CalendLigne2 += "<td><b>" + t_ListeJours[s] + "</b></td>";
}
a = 0;
CalendLigneSuiv = "";
//===============ligneSuiv
for (i=(1-rechercheJourCle(anSouh,moisSouh,1)); i<t_LongMaxMois[moisSouh]; i++) {
CalendLigneSuiv += "<tr align=center>";
if ((ligneUne+a) == ligneRef) {
CalendLigneSuiv += "<td><b><font color=#cc0000>" + ligneRef + "</font></b></td>";
} else {
CalendLigneSuiv += "<td><font color=#888888>" + (ligneUne+a) + "</font></td>";
}
for (j=1; j<8; j++) {
if ((i+j) <= 0) {
CalendLigneSuiv += "<td> </td>";
} else if ((i+j) == jourSouh) {
CalendLigneSuiv += "<td><b><font color=#ff0000>" + (i+j) + "</font></b></td>"; }
} else if ((i+j) > t_LongMaxMois[moisSouh]) {
CalendLigneSuiv += "<td> </td>";
} else {
CalendLigneSuiv += "<td>" + (i+j) + "</td>";
}
}
CalendLigneSuiv += "</tr>";
//fin de ligne et bouclage ligne suivante a++;
i = i + 6;
}
//affichage calendrier dans le <div>
Calendrier.innerHTML = CalendLigne1 + CalendLigne2 + CalendLigneSuiv + "</table>";
}
Comment rechercher ce jour clé qui est le n° du jour de la semaine auquel on ajoute 1, puis que le jour d'indice 0 est "Jour" dans notre variable t_ListeJours.
/* *************************
pour rechercher le numero du jour de la semaine correspondant a la date souhaitée
************************* */
function rechercheJourCle(yy,mm,dd) {
return Math.floor((dateEnJours(yy,mm,dd)-2) % 7) + 1;
}
/* *************************
pour transformer la date reçue en paramètre
en un nbre de jours depuis l'an 'zéro' du calendrier grégorien proleptique
************************* */
function dateEnJours(yyy,mmm,ddd) {
//si au-delà de février
if (mmm > 2) {
var nbrAnnBis = Math.floor(yyy/4) - Math.floor(yyy/100) + Math.floor(yyy/400);
var nbrJoursAnnee = yyy * 365 + nbrAnnBis;
var nbrJoursMois = (mmm-1) * 31 - Math.floor(mmm * 0.4 + 2.3);
return (nbrJoursAnnee + nbrJoursMois + ddd);
} else {
// si janvier ou fevrier
var anPrecedent = yyy-1;
var nbrAnnBis = Math.floor(anPrecedent/4) - Math.floor(anPrecedent/100) + Math.floor(anPrecedent/400);
var nbrJoursAnnee = yyy * 365 + bis;
var nbrJoursMois = (mmm-1) * 31;
return (nbrJoursAnnee + nbrJoursMois + ddd);
}
}
Et enfin, la fonction defLigne
qui reçoit la date du jour en paramètre (de 1 à maximum 31) et qui détermine sur quelle ligne il faudra afficher cette date du jour.
/* ******************************
pour retrouverle numero de la semaine correspondant a la date en paramètre
********************************* */
function defLigne(dd) {
nbrJ = 0;
nbrS = 0;
for (n=1; n<moisSouh; n++) {
nbrJ += t_LongMaxMois[n];
}
nbrJ = nbrJ + dd - (9 - rechercheJourCle(anSouh,1,1));
nbrS = Math.floor(nbrJ / 7) + 1;
if (rechercheJourCle(anSouh,1,1) == 1) {
nbrS++;
}
return nbrS;
}
Et, juste pour voir que tout ceci fonctionne correctement, voilà le résulat de notre programmation.
À nous de réfléchir pour voir les améliorations à apporter à ce calendrier perpétuel de base. Ce sera l'objet de notre chapitre 51.
voir suite >>>
voir suite >>>