Lors de la pratique de son métier, un développeur sera assurément amené à manipuler des dates.
À moins d’une raison très particulière, il ne faudrait pas réinventer la roue et plutôt faire usage des classes prenant déjà en charge la problématique des dates (et de l’heure).
Qt, par exemple, met à disposition les classe QDate et QDateTime.
Mais lorsqu’on apprend la programmation, les exercices sur les dates sont des classiques. Voici ce qui est souvent demandé :
- déterminer si une année donnée est bissextile ;
- déterminer le jour de la semaine d’une date donnée ;
- convertir l’année d’une date en chiffres romains (et vice-versa).
Je reviendrai certainement sur la conversion d’un chiffre arabe en chiffre romain (et vice-versa) dans un autre billet.
Déterminer si une année est bissextile
Pour le calendrier grégorien (celui que l’on utilise de nos jours), une année (le temps que met la Terre pour faire un tour complet autour du Soleil) dure 365.2425 jours.
Avec ce calendrier la méthode pour déterminer si une année donnée est bissextile est la suivante :
- Une année est bissextile si elle se divise par 4.
- Une année n’est pas bissextile si elle se divise par 100.
- Toutefois, si elle se divise par 400, elle est bissextile.
bool isLeapYear(int Year) { return (Year % 400 == 0 || (Year % 4 == 0 && Year % 100 != 0) ); }
Mais ce calcul n’est valable qu’avec le calendrier grégorien. Or, celui-ci a été introduit le 15 octobre 1582 par le pape Grégoire XIII.
Pour toutes les années qui précèdent 1582, c’est le calendrier julien qui fait foi. Ce calendrier est basé sur une année de 365.25 jours, ce qui signifie qu’il y a une année bissextile tous les 4 ans.
Notre méthode de calcul peut donc être améliorée :
bool isLeapYear(int Year) { if (Year < 1582) return abs(Year) % 4 == 0; else return (Year % 400 == 0 || (Year % 4 == 0 && Year % 100 != 0) ); }
Déterminer le jour de la semaine
La méthode permettant de déterminer quel jour de la semaine est une date donnée est différente selon que la date fait partie du calendrier grégorien ou julien.
Le calendrier julien se termine le 4 octobre 1582. Le calendrier grégorien commence le 15 octobre 1582. Cela signifie que le jour qui suit la date du 4 octobre 1582 est le 15 octobre 1582. Les dates comprises entre le 5 et le 14 octobre 1582 n’existent pas.
prérequis : Jour (1 - 31), Mois (1-12), Année variables : DécaleAn, MoisDécalé, An, NuméroJour : entiers début DécaleAn <- (14 - Mois) / 12 An <- Année - DécaleAn MoisDécalé <- Mois + 12 * DécaleAn - 2 si (Année > 1582) ou (Année = 1582 et (Mois > 10) ou (Mois = 10 et Jour >= 15))) alors NuméroJour = (Jour + Année + An/4 - An/100 + An/400 + 31 * Mois / 12) modulo 7 sinon si (Année < 1582) ou (Année = 1582 et (Mois < 10 ou (Mois = 10 et Jour <= 4))) alors NuméroJour = (5 + Jour + An + An / 4 + ( 31* Mois / 12) modulo 7 sinon NuméroJour = erreur fin si fin si fin
NuméroJour vaut 0 pour dimanche, 1 pour lundi, etc.
En C++, la fonction pourrait être la suivante :
int dayOfWeek(int Jour, int Mois, int Annee) { int DecaleAn = 14 - Mois / 12; int An = Annee - DecaleAn; int MoisDecale = Mois + 12 * DecaleAn - 2; int NumeroJour = 0; if ( (Annee > 1582) || (Annee == 1582 && (Mois > 10) || (Mois == 10 && Jour >= 15))) ) NumeroJour = (Jour + Annee + An/4 - An/100 + An/400 + 31 * Mois / 12) % 7; else if ( (Annee < 1582) || (Année == 1582 && (Mois < 10 || (Mois == 10 && Jour <= 4))) ) NumeroJour = (5 + Jour + An + An / 4 + ( 31* Mois / 12) % 7; else NumeroJour = -1; return NumeroJour; // 0 : dimanche, 1 : lundi, etc. -1 : erreur }