ACCUEIL EO | FR | EN

TAGNUMERILO

L'original de cet article est rédigé en espéranto, langue internationale équitable, dans laquelle tagnumerilo se décompose ainsi :

Si votre navigateur internet n'autorise pas JavaScript, vous ne pouvez ni voir ni utiliser le numéroteur de jours JavaScript ci-dessous :

Pourquoi numéroter les jours ?

Combien de jours séparent deux dates calendaires ?

Quelle date est à tant de jours de telle date ?

Les questions de ce genre semblent plus simples à poser qu'à résoudre, tant les systèmes de calcul du temps, c'est-à-dire les calendriers, paraissent irréguliers et pleins d'exceptions. C'est pourquoi les algorithmes habituels de calendriers perpétuels utilisent des tables pour calculer le numéro de jour de toute date, selon une numérotation séquentielle, à partir de laquelle le problème se réduit à une simple différence arithmétique entre deux numéros de jours.

Cet article présente un algorithme de numérotation des jours sans tables, ainsi que son inverse (du numéro de jour à la date), pour le calendrier Grégorien en vigueur en occident, ou son prédécesseur Julien plus simple, encore utilisable de nos jours sur une période de deux siècles. Comme les deux algorithmes ne nécessitent qu'une simple arithmétique entière, avec seulement des nombres entiers (sans virgule) et des divisions entières (c'est-à-dire avec un quotient et un reste entiers), ils conviennent particulièrement aux moyens de calcul simples, tels le calcul manuel ou les microcontrôleurs les moins chers (et les plus répandus).

Les faits du calendrier

Le globe terrestre fait une révolution autour de son axe pôlaire en un jour par rapport au soleil, et autour du soleil en une année par rapport aux étoiles lointaines. L'angle constant entre ces deux axes de révolution cause les saisons, avec lesquelles tentent de se synchroniser les calendriers dits "solaires", tels le Grégorien et le Julien. La mesure astronomique actuelle d'une année égale environ 365,2422 jours.

Le calendrier Julien fut institué par l'empereur romain Julius Cézar en 45 av. J.-C. sur les conseils d'astronomes égyptiens. Son année comprend 365 jours, répartis entre les 12 mois actuels, plus un "jour intercalaire", ajouté le 29 février chaque "année bissextile" multiple de quatre. Cette approximation de la durée de l'année, en moyenne 365,25 jours, excellente par rapport aux outils astronomiques de l'époque, retarde cependant le calendrier Juilen d'environ 3 jours tous les quatre siècles.

Seize siècles plus tard, pour combler ce retard devenu trop évident, le calendrier Grégorien fut instauré par le pape catholique Grégoire XIII en 1582. D'une part il améliora l'approximation de la durée de l'année, à en moyenne 365,2425 jours, en sautant le jour intercalaire de chaque année multiple de 100 mais pas de 400, c'est-à-dire de 3 jours intercalaires tous les quatre siècles, et d'autre part il resynchronisa le calendrier par un saut de 10 jours : le lendemain du jeudi 4/10/1582 fut le vendredi 15/10/1582.

Le changement, du calendrier Julien au Grégorien, ne fut pas immédiatement accepté par tous les pays : vinrent d'abord les catholiques (par exemple la France à partir du lundi 20/12/1582), puis plus tard les protestants (par exemple l'Angleterre à partir du jeudi 14/8/1752), et encore plus tard les orthodoxes (par exemple la Russie à partir du jeudi 14/2/1918).

Algorithme en entiers sans tables

Choisissons d'abord le 1er Mars pour origine de la période annuelle (et donc numérotons janvier=13 et février=14), à la fin de laquelle se retrouve ainsi reporté l'occasionel jour intercalaire. Cela fait aussi apparaître une période de 5 mois de 31+30+31+30+31 = 153 jours :
mois (m) : 3 4 5 6 7 8 9101112 1314
nombre de jours : 313031303131303130313128
période : 153 153
(((m+1)*153)/5)-122 0316192122153184214245275306337

Un tantinet d'attention, portée à la suite des multiples de 153/5 et de leurs différences, révèle facilement la formule de la quatrième ligne du tableau, qui égale la somme des nombres de jours des mois compris entre le 1er Mars et le 1er du mois "m" ; ajoutez le quantième du mois de la date pour obtenir le nombre de jours entre le 1er Mars et la date en question.

Entre le 1er Mars d'une année bissextile de base (multiple de 400 pour le calendrier Grégorien, ou de 4 pour le Julien), et le 1er Mars de la "a"-ième année suivante, le nombre de jours est (a*365)+(a/4)-(a/100)+(a/400) pour le calendrier Grégorien (ou plus simplement (a*365)+(a/4) pour le Julien).

Voici donc l'algorithme de numérotation des jours, avec A=année M=mois J=jour, et NG ou NJ = numéro du jour selon le calendrier Grégorien ou Julien :

Pour trouver le jour de la semaine de la date, diviser N en périodes hebdomadaires de 7 jours (il est remarquable que la période Grégorienne quadri-séculaire de 146097 jours soit multiple de 7); le reste de la division euclidienne donne :
reste : 0123456
Julien (B=0) : lunmarmerjeuvensamdim
Grégorien : merjeuvensamdimlunmar

Exemple : 3/9/2005, A=2005 M=9 J=3, a=5 m=9, NJ=NG=2012=7*287+3=samedi.

Algorithme inverse

Premièrement, diviser le numéro de jour NG en périodes quadri-séculaires de 146097 jours : NG=146097*Q+R (c-à-d Q et R sont le quotient et le reste de la division euclidienne NG/146097). Si R=146096, la date est le dernier jour intercalaire de la période quadri-séculaire, le 29 février de l'année A=B+Q*400+400.

Sinon, deuxièmement diviser R en périodes séculaires de 36524 jours : R=36524*C+c. Les deux premières étapes ne valent que pour le calendrier Grégorien ; pour le Julien, démarrer ici avec c=NJ.

Troisièmement diviser c en périodes quadri-annuelles de 1461 jours : c=1461*q+r. Si r=1460, la date est un jour intercalaire, le 29 février de l'année J=B+Q*400+C*100+q*4+4.

Sinon, quatrièmement diviser r en périodes annuelles de 365 jours : r=365*i+j, et calculer a=B+Q*400+C*100+q*4+i, et m=(((j+31)*5)/153)+2, et J=j-(((m+1)*153)/5)+123.

Finalement, si m>12, calculer A=a+1 et M=m-12, sinon A=a et M=m. La date est A=année M=mois J=jour.

Exemple : NJ=2012, q=1 r=551, i=1 j=186, a=2005 m=9 J=3, A=2005 M=9, 3/9/2005.

Usages de l'algorithme Julien

D'une part, 16 à 19 siècles d'histoire ont été datés selon le calendrier Julien. Par exemple, durant la vie de Zamenhof (concepteur de la langue internationale équitable Espéranto), les russes utilisaient encore le calendrier Julien (jusqu'à son mercredi 31 janvier 1918, qui était le 13 février Grégorien), alors 13 jours en retard sur le Grégorien, utilisé par les occidentaux depuis déjà trois siècles.

D'autre part, les microcontrôleurs calculent plus économiquement avec des nombres de 16 bits, entre 0 et 65535, soit le nombre de jours d'environ 180 ans. Comme entre le 1/3/1900 et le 28/2/2100 les années bissextiles Grégoriennes et Juliennes coincident, on peut utiliser l'algorithme Julien plus simple, avec par exemple l'an 1900 pour base (1/3/1900 = jour numéro 0, jusqu'au jour numéro 65535 = 5/5/2079).

Codages

En JavaScript :
voir au début du code source HTML de cette page
En langage C :
static int gregorien = 1; // 1:Gregorien 0:Julien
typedef struct{int jour, mois, an;} date; // 1..31, 1..12, ..2005..
int numerojour(date d) { // convertit date en numero de jour
  if(mois<3){ d.an-=1; d.mois+=12; } // decaler origine au 1er mars
  return d.an*365 + d.an/4 + (gregorien ? -d.an/100 + d.an/400 : 0)
       + (d.mois+1)*153/5-123 + d.jour;
}
int joursemaine(int n) { // convertit numero de jour en :
  return (gregorien ? n+2 : n) % 7; // 0=lundi .. 6=dimanche
}  
void datejour(int n, date *d) { // convertit numero de jour en date
  int m, a=0;
  if(gregorien) {
    m = n/146097;  a += m*400;  n -= m*146097; // periodes 400 ans
    if(n==146096) { d->an=a+400; d->mois=2; d->jour=29; return; }
    m = n/36524;   a += m*100;  n -= m*36524;  // periodes 100 ans
  }
  m = n/1461;  a += m*4;  n -= m*1461; // periodes 4 ans
  if(n==1460) { d->an=a+4; d->mois=2; d->jour=29; return; }
  m = n/365;   a += m;    n -= m*365;  // periodes 1 an
  m = (n+31)*5/153+2;     n -= (m+1)*153/5-123;
  if(m>12) { a+=1; m-=12; } // recaler origine au 1er janvier
  d->an=a; d->mois=m; d->jour=n; return;
}
En Forth :
1 value gregorien  \ 1:Gregorien 0:Julien
: date>  \ j m a -- n ; convertit date j/m/a en numero du jour n
  >r  dup 3 < IF 12 + r> 1- >r THEN  \ decaler origine au 1er mars
  1+ 153 * 5 / 123 -  +  \ -- n | a ; n jours du 1/3/a au j/m/a
  r@ 4 / +  gregorien IF r@ 100 / - r@ 400 / + THEN  r> 365 * +
;
: >jsem  \ n -- s ; convertit numero de jour n en :
  gregorien IF 2 + THEN  7 mod  \ 0:lundi .. 6:dimanche
;
: >date  \ n -- j m a ; convertit numero de jour n en date j/m/a
  0 >r  gregorien IF
    146097 /mod 400 * r> + >r  \ periodes 400 ans
    146096 over = IF drop 29 2 r> 400 + exit THEN
    36524  /mod 100 * r> + >r  \ periodes 100 ans
  THEN  \ -- n | a
  1461 /mod 4 * r> + >r  \ periodes 4 ans
  1460 over = IF drop 29 2 r> 4 + exit THEN
  365  /mod     r> + >r  \ periodes 1 an
  dup 31 + 5 * 153 / 2 +  tuck 1+ 153 * 5 / 123 - - swap  \ -- j m | a
  dup 12 > IF 12 - r> 1+ >r THEN  r>  \ -- j m a
;

Liens

CL20080702