Cet exercice ainsi que sa correction est proposé par Philippe Moutou. Il enseigne au lycée Henri IV à Paris.

Exercice

Écrire une fonction calendrier(j,m,a) qui affiche un petit calendrier de la semaine lorsqu’on lui fournit en argument la date du dimanche. Si on entre calendrier(29,4,18) (29 avril 2018), ce programme doit nous afficher : Lundi 30 avril 2018, Mardi 1 mai 2018, …, Dimanche 6 mai 2018.

Corrigé

image 1
Il faut penser à traiter tous les cas (semaine à cheval sur deux mois ou deux années, années bissextiles). Ce programme nécessite qu’on lui fournisse le nom et la longueur des mois ainsi que la règle concernant les années bissextiles. J’ai simplifié le problème en ne traitant que les années après le 01/01/2000. Dans cette version, il faut entrer la date du dimanche qui précède la semaine (ce qui était demandé) mais cela amoindrit l’intérêt d’un tel programme.

def calendrier(j,m,a):
  nom_jours=['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche']
  nom_mois=['janvier','fevrier','mars','avril','mai','juin','juillet','aout','septembre','octobre','novembre','decembre']
  long=[31,28,31,30,31,30,31,31,30,31,30,31]
  if a%4==0 and not a==0:
    long[1]=29
  semaine,jour,mois,annee=[],j,m,2000+a
  while len(semaine)<7:
    jour=jour+1
    if jour>long[mois-1]:
      mois=mois+1
      jour=1
      if mois==13:
        mois=1
        annee=annee+1
    semaine.append([nom_jours[len(semaine)],str(jour),nom_mois[mois-1],str(annee)])
  return semaine
  
Cal=calendrier(13,05,2018)
for i in range(7):
  print(" ".join(Cal[i]))

On peut imaginer qu’il serait plus utile si, en fournissant la date du jour, par exemple 27 décembre 2018 sous la forme du triplet (27,12,18), le programme se charge de trouver le jour de la semaine correspondant à cette date et affiche la semaine qui suit cette date.
Dans le programme qui suit, pour déterminer le jour de la semaine, le module jourSemaine(j,m,a) calcule le nombre de jours écoulés entre le 01/01/2000 qui était un samedi et la date du jour (j,m,a).

def calendrier(j,m,a):
  if a%4==0:
    long[1]=29
  semaine,jour,mois,annee=[],j,m,2000+a
  while len(semaine)<7:
    semaine.append([nom_jours[(len(semaine)+JS)%7],str(jour),nom_mois[mois-1],str(annee)])
    jour=jour+1
    if jour>long[mois-1]:
      mois=mois+1
      jour=1
      if mois==13:
        mois=1
        annee=annee+1
  return semaine
  
def jourSemaine(j,m,a):
  an,mo,jo=0,1,5 #le 1er janvier 2000 était un samedi (j=5)
  while an<a:
    if an%4==0:
      jo+=366
    else:
      jo+=365
    an+=1
  while mo<m:
    if a%4==0 and mo==2:
      jo+=long[mo-1]+1
    else:
      jo+=long[mo-1]
    mo+=1
  jo+=j-1
  return jo%7
 
jourJ,moisM,anA=27,12,18 #entrer ici la date du jour désiré (après le 01/01/00)
nom_jours=['Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche']
nom_mois=['janvier','fevrier','mars','avril','mai','juin','juillet','aout','septembre','octobre','novembre','decembre']
long=[31,28,31,30,31,30,31,31,30,31,30,31]
JS=jourSemaine(jourJ,moisM,anA)
Cal=calendrier(jourJ,moisM,anA)
for i in range(7):
  print(" ".join(Cal[i]))

image 2
Trois listes sont fixes ici et permettent de donner le nom des jours (nom_jours), des mois (nom_mois) et la longueur des mois d’une année ordinaire (long). La liste semaine, par contre, est variable, remplie progressivement avec les jours de la semaine cherchés. On peut prolonger ce type de programme pour obtenir l’affichage d’un mois ou d’une année-type (sans tenir compte des années bissextiles, il n’y a que 7 types d’années : celles qui commencent un lundi, celles qui commencent un mardi, etc.). On peut aussi déterminer la phase de la Lune…