Bonjour,
Suite aux explications données par @bricoleau sur sa fonction :
uint8_t _RTCcalculerJoursem(uint8_t annee, uint8_t mois, uint8_t jour)
{
//Formule maison, économe en calculs fin d'épargner le petit processeur 8 bits
uint8_t somme = annee + (annee >> 2) + jour;
switch (mois)
{
case 2 :
case 3 :
case 11 : somme++; break;
case 6 : somme += 2; break;
case 9 :
case 12 : somme += 3; break;
case 4 :
case 7 : somme += 4; break;
case 1 :
case 10 : somme += 5; break;
case 5 : somme += 6;
}
if (mois > 2 || (annee & 3)) somme++;
return somme % 7;
}
Histoire de faire un peu de code j'ai voulu créer une toute petite librairie pour pouvoir calculer à partir de cet algorithme de calcul (celui de bricoleau) le jour de la semaine sur plusieurs siècles et en passant par le moniteur série. Au final j'en ai créer deux :
pour les deux, l'exemple et le header sont identiques :
1/ exemple :
#include "Dow.h"
void setup() {
Serial.begin(115200);
}
void loop() {
uint8_t quelleDate[4];
Serial.println(F("siècle : 4 (1700 à 1799) - 2 (1800 à 1899) - 0 (1900 à 1999) - 6 (2000 à 2099)"));
Serial.println(F("(4 couvre également de 2100 à 2199 - 0 couvre également de 1582 à 1599"));
Serial.println(F("2 couvre également de 2200 à 2299 - 6 couvre également de 1600 à 1699)"));
Serial.println(F("Saisir le siècle :"));
quelleDate[0] = entree();
Serial.println(quelleDate[0]);
Serial.println(F("Saisir le jour :"));
quelleDate[1] = entree();
Serial.println(quelleDate[1]);
Serial.println(F("Saisir le mois :"));
quelleDate[2] = entree();
Serial.println(quelleDate[2]);
Serial.println(F("Saisir l'année :"));
quelleDate[3] = entree();
Serial.println(quelleDate[3]);
Serial.print (quelleDate[1]); Serial.print (F("/"));
Serial.print (quelleDate[2]); Serial.print (F("/"));
if (quelleDate[0] == 4) Serial.print(F("17"));
else if (quelleDate[0] == 2) Serial.print(F("18"));
else if (quelleDate[0] == 0 ) Serial.print(F("19"));
else if (quelleDate[0] == 6 ) Serial.print(F("20"));
(quelleDate[3] < 10) ? Serial.print(F("0")) : Serial.print(F(""));
Serial.print (quelleDate[3]); Serial.print (F(" = "));
Dow quelJour (quelleDate[0], quelleDate[1], quelleDate[2], quelleDate[3]);
quelJour.affiche();
}
uint8_t entree()
{
char caractere;
while (!Serial.available());
uint8_t chiffre = Serial.parseInt();
while (Serial.readBytes(&caractere, 1) != 0) {
if (caractere == '\r') {
break;
}
}
return chiffre;
}
2/ header :
#ifndef Dow_h
#define Dow_h
#include <stdint.h>
#include <arduino.h>
class Dow {
public:
// Constructeur
Dow(uint8_t siecle, uint8_t d, uint8_t m, uint8_t y);
void affiche(void);
// Destructeur
~Dow();
private:
uint8_t _siecle;
uint8_t _d;
uint8_t _m;
uint8_t _y;
};
#endif
3/ 1ère version du CPP :
#include "Dow.h"
const char leJour [7][9] PROGMEM = {"dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"};
uint8_t dowPlus[12];
bool bissextile (uint8_t s, uint8_t annee) {
if ((s == 4) && ((annee & 3) == 0) && (annee != 0)) return true; // 1700 à 1799
else if ((s == 2) && ((annee & 3) == 0) && (annee != 0)) return true; // 1800 à 1899
else if ((s == 0) && ((annee & 3) == 0) && (annee != 0)) return true; // 1900 à 1999
else if ((s == 6) && ((annee & 3) == 0)) return true; // 2000 à 2099
else return false;
}
void calcul( uint8_t s) {
dowPlus[0] = (0 + s) % 7;
dowPlus[1] = (31 + s) % 7;
dowPlus[2] = (59 + s) % 7;
dowPlus[3] = (90 + s) % 7;
dowPlus[4] = (120 + s) % 7;
dowPlus[5] = (151 + s) % 7;
dowPlus[6] = (181 + s) % 7;
dowPlus[7] = (212 + s) % 7;
dowPlus[8] = (243 + s) % 7;
dowPlus[9] = (273 + s) % 7;
dowPlus[10] = (304 + s) % 7;
dowPlus[11] = (334 + s) % 7;
}
//commun
uint8_t calcDow( uint8_t siecle, uint8_t jour, uint8_t mois, uint8_t annee) {
uint8_t dow = annee + (annee >> 2) + jour;
switch (mois) {
case 1 : dow += dowPlus[0]; break;
case 2 : dow += dowPlus[1]; break;
case 3 : dow += dowPlus[2]; break;
case 4 : dow += dowPlus[3]; break;
case 5 : dow += dowPlus[4]; break;
case 6 : dow += dowPlus[5]; break;
case 7 : dow += dowPlus[6]; break;
case 8 : dow += dowPlus[7]; break;
case 9 : dow += dowPlus[8]; break;
case 10 : dow += dowPlus[9]; break;
case 11 : dow += dowPlus[10]; break;
case 12 : dow += dowPlus[11]; break;
}
if ((mois < 3) && (bissextile (siecle, annee))) dow--; // annee bissextile
return dow % 7;
}
// Initialisation classe Dow
Dow::Dow(uint8_t siecle, uint8_t d, uint8_t m, uint8_t y)
: _siecle(siecle),
_d(d),
_m(m),
_y(y)
{}
void Dow::affiche() {
calcul( _siecle);
Serial.println((__FlashStringHelper*) leJour[calcDow(_siecle, _d, _m, _y)]);
Serial.print('\n');
}
// Destruction
Dow::~Dow() {}
4/ 2ème version du CPP :
#include "Dow.h"
const char leJour [7][9] PROGMEM = {"dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"};
const uint16_t base[12] PROGMEM = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
uint16_t dowPlus[12];
uint16_t *pn;
void copie(uint16_t tableauOriginal[], uint16_t tableauCopie[], uint8_t tailleTableau)
{
for (uint8_t y = 0 ; y < tailleTableau ; y++)
*(tableauCopie + y) = pgm_read_word_near(tableauOriginal + y);
}
bool bissextile (uint8_t s, uint8_t annee) {
if ((s == 4) && ((annee & 3) == 0) && (annee != 0)) return true; // 1700 à 1799
else if ((s == 2) && ((annee & 3) == 0) && (annee != 0)) return true; // 1800 à 1899
else if ((s == 0) && ((annee & 3) == 0) && (annee != 0)) return true; // 1900 à 1999
else if ((s == 6) && ((annee & 3) == 0)) return true; // 2000 à 2099
else return false;
}
void calcul( uint8_t s) {
pn = dowPlus;
for (uint8_t z = 0; z < 12; z++) {
*pn = (*pn + s) % 7;
pn++;
}
}
//commun
uint8_t calcDow( uint8_t siecle, uint8_t jour, uint8_t mois, uint8_t annee) {
pn = dowPlus;
uint8_t dow = annee + (annee >> 2) + jour;
for ( uint8_t x = 1 ; x < 13 ; x++) {
if (mois == x) dow += *pn;
pn++;
}
if ((mois < 3) && (bissextile (siecle, annee))) dow--; // annee bissextile
return dow % 7;
}
// Initialisation classe Dow
Dow::Dow(uint8_t siecle, uint8_t d, uint8_t m, uint8_t y)
: _siecle(siecle),
_d(d),
_m(m),
_y(y)
{}
void Dow::affiche() {
copie (base, dowPlus, 12);
calcul( _siecle);
Serial.println((__FlashStringHelper*) leJour[calcDow(_siecle, _d, _m, _y)]);
Serial.print('\n');
}
// Destruction
Dow::~Dow() {}
La deuxième version est "optimisée" (je mets des guillemets car c'est moi qui le pense) mais utilise des tableaux sur 2 octets.
Conclusion :
- Ce fut un bon entrainement en ce qui me concerne pour coder et pour comprendre ;
- le code de Sakamoto et la méthode de Zeller sont bien plus efficaces que mes petites librairies mais avec l'inconvénient de travailler sur deux octets si on utilise un AVR 8 bits (tout comme ma deuxième version) ;
- le code de @bricoleau est particulièrement efficace pour sa librairie et sur AVR, il a l'avantage de ne porter que sur un siècle et ça suffit dans le cadre de son utilisation ...
Voilà ça n'intéressera certainement pas grand monde mais c'est une synthèse pour moi et qui sait même si une seule personne est intéressée par mon travail ça suffira ![]()
Bonne journée.