De: Laurent Longre Objet: Pour Eric, Flo, Frédéric et les autres Date : dimanche 26 novembre 2000 16:01 Quelques esseuplications sur ma formule de calcul du numéro de série d'une date (cf ficelle "Le Christ est né un samedi", sdn, vendredi 14:38). Je serai bref. :-))))))))))))))) ----------------------------- Pour calculer le numéro de série d'une date, il faut additionner : - Les annés entières entre cette date et 1900 (en nombre de jours) - Les mois précédant la date dans l'année (toujours en nombre de jours) - Les jours restant (J) Par exemple, pour la date du 25/4/2149, le numéro de série sera donné par l'addition du nombre de jours entre le 1/1/1900 et le 31/12/2148 (annés entières), plus le nombre de jours entre le 1/1/2149 et le 31/3/2149 (mois entiers), plus le nombre de jours restants, 25. Jours des annés entières = 90946 + jours des mois entiers = 91 + jours restants = 25 Total = 91062. C'est le numéro de série du 25/4/2149. 1) Pour le nombre de jours correspondant aux annés entières, on a déjà un début avec (A-1900)*365. A quoi il faut ajouter autant de jours qu'il y a d'annés bissextiles dans la période. Une année est bissextile si elle est divisible par 4, ou par 400 si elle est un multiple de 100. Pour éviter ces tests, on peut donner une formulation arithmétique de cette définition. Le nombre d'annés bissextiles dans la période, c'est: - Le nombre d'annés divisibles par 4 - Plus le nombre d'annés divisibles par 400 - Moins le nombre d'annés divisibles par 100 Soit ENT((A-1901)/4)+ENT((A-1601)/400)-ENT((A-1901)/100) Pourquoi 1901? Parce qu'il faut le nombre d'annés entre 1900 et A-1 (nombre d'annés pleines dans la période). A-1-1900 = A-1901. Et pourquoi 1601? Parce que la 1ère année bissextile multiple de 400, c'est l'an 2000. Il faut donc que pour la période 2000-2400 le nombre d'annés "bissextiles par 400" soit égal à 1. Donc prendre 1600 comme date de base pour la soustraction. Si on gardait 1900, ENT((2000-1901)) donnerait par exemple zéro, ce qui ne convient pas. (A-1900)*365+ENT((A-1901)/4)+ENT((A-1601)/400)-ENT((A-1901)/100) donne donc déjà le nombre de jours du numéro de série en annés pleines, en prenant en compte toutes les annés bissextiles. [ Vous suivez toujours ? :-))))))))))) Bon, reprenons... ] 2) Il nous faut maintenant additionner le nombre de jours constituant les mois pleins dans l'année considéré. Ce qui pose deux problèmes : => Problème 1. Les mois peuvent comporter 28, 29, 30 ou 31 jours. Pour tenir compte de ça, on peut construire un tableau de 12 valeurs contenant: - 0 (pour janvier) - Nombre de jours de janvier : 31 - Nombre de jours de janvier+février : 59 - Nombre de jours de janvier+février+mars : 90 - Etc. jusqu'à janvier+...+novembre ... et ensuite obtenir à partir de ce tableau le nombre de jours cumulés entre janvier et le mois M-1 par la fonction INDEX: INDEX({0;31;59;90;120;151;...;334};M). Pour raccourcir un peu la formule, on peut aussi partir d'un nombre moyen de (M-1)*30 (30 jours par mois) et ajouter seulement le décalage entre le cumul des jours "réls" par mois et ce cumul par mois de 30 jours. Ces décalages donnent le tableau {1;2;0;1;1;2;2;3;4;4;5;5}. Et (M-1)*30+INDEX({1;2;0;1;1;2;2;3;4;4;5;5};M) donne donc la partie "nombre de jours des mois pleins" du numéro de série. [Oufff. Petite pause clope, permettez... :-' Flo, si tu es toujours là, sache qui tu as atteint 9,9/10 dans mon échelle d'estime et que c'est exceptionnel, seule ma maman a atteint ce palier avant toi. :-)))))] => Problème 2. A ce nombre, il faut ajouter 1 si l'année est bissextile et si la date est postérieure au 28/2. Pour tester si la date est postérieure au 28/2, on peut transformer M et J en un seul nombre: M*100+J et faire le test sur ce nombre. Par exemple: - Si M=4 et J=2, M*100+J = 402 > 228 (228=28 février). Cette date est donc postérieure au 28 février. - Si M=2 et J=14, M*100+J = 214 < 228. Cette date est antérieure au 28/2 et la "bissextilité" (?!?) éventuelle de l'année ne doit pas être prise en compte. (M*100+J>228) donne donc 1 si la date est > 28/2, et sinon zéro. Il reste à multiplier la valeur de ce test par (1 si année bissextile, 0 sinon). Sur le même principe qu'au début, on détermine si la date est bissextile par additions-soustraction en partant des restes de division par 4, 100 et 400: (MOD(A;4)=0)+(MOD(A;400)=0)-(MOD(A;100)=0) => donne 1 si l'année est bissextile, 0 sinon. Cette expression peut être un peu raccourcie sous la forme équivalente: SOMME((MOD(A;{4;400;100})=0)*{1;1;-1}) Donc : (M*100+J>228)*SOMME((MOD(A;{4;400;100})=0)*{1;1;-1}) ajoute 1 au numéro de série si la date est après le 28/2 et si l'année est bissextile. Et : (M-1)*30+INDEX({1;2;0;1;1;2;2;3;4;4;5;5};M)+(M*100+J>228) *SOMME((MOD(A;{4;400;100})=0)*{1;1;-1}) ... donne le nombre de jours des mois pleins de notre numéro de série. 3) Il ne reste plus qu'à ajouter les jours supplémentaires, J : =(A-1900)*365+ENT((A-1901)/4)+ENT((A-1601)/400)-ENT((A-1901)/100) +30*(M-1)+INDEX({1;2;0;1;1;2;2;3;4;4;5;5};M)+(M*100+J>228) *SOMME((MOD(A;{4;400;100})=0)*{1;1;-1})+J Et voilà notre numéro de série. A noter que, comme l'an zéro n'existe pas dans le calendrier grégorien, l'année précédant l'an 1 est l'an -1. Pour tenir compte de ce décalage, si l'on veut des numéros de série de dates avant J.C, il faut ajouter 1 à l'année quand A<0. Voici donc une formule un peu plus historiquement correcte (mais pas mathématiquement), sur laquelle je vais arrêter parce que tout ça commence à me casser ces choses que Bernard -le veinard- a en triple exemplaire alors que je n'en ai qu'une seule paire, et je ne parle pas des plumes: =(A+(A<0)-1900)*365+SOMME(ENT((A+(A<0)-{1901;1601;1901})/{4;400;100}) *{1;1;-1})+30*(M-1)+INDEX({1;2;0;1;1;2;2;3;4;4;5;5};M)+(M*100+J>228) *SOMME((MOD(A+(A<0);{4;400;100})=0)*{1;1;-1})+J Et donc, dans le calendrier grégorien, le petit Jésus est bien né un lundi. Comme moi. :-))))))))))))))) Sur ce, bonne fin de week-end et GROS BISOUS à toutes et à tous. Laurent P.S. pour Frédéric : ce que je voulais dire par "cette formule n'est pas adapté au calendrier 1904", c'est que le numéro de série calculé est celui du calendrier 1900. Il n'est pas cohérent avec celui du calendrier 1904 (jour 1 = 1er janvier 1904). On ne pourrait donc pas, par exemple, combiner dans des calculs cette formule avec les résultats de la fonction DATE. Le numéro de série au calendrier 1904 correspond à cette formule: =(A+(A<0)-1904)*365+SOMME(ENT((A+(A<0)-{1905;1605;1905})/{4;400;100}) *{1;1;-1})+30*(M-1)+INDEX({0;1;-1;0;0;1;1;2;3;3;4;4};M)+(M*100+J>228) *SOMME((MOD(A+(A<0);{4;400;100})=0)*{1;1;-1})+J ... ou alors à la précédente en ajoutant -1462 à la fin.