Si certains exercices n'ont pas pu être terminés dans le cadre de cette séance, il est fortement conseillé de les terminer par vous-même chez vous ou en salle libre service.
Le but de ce TP est de commencer l'apprentissage d'une démarche d'analyse descendante d'un problème donné.
Le morceau de code suivant, à recopier tel quel dans votre fichier permet de gérer des dates "naïves" constituées d'un jours, d'un mois et d'une année.
Note : cette représentation des dates est volontairement naïve. Elle a pour but de vous obliger à utilisez les fonctions de création et d'accès aux dates...
import pickle def nouvelle_date(jour, mois, annee): """créé une nouvelle date à partir de trois nombres entiers : un numéro de jours, un numéro mois et un numéro d'année. """ return pickle.dumps((jour, mois, annee)) def no_jour(date): """renvoie le numéro du jours correspondant à la date donnée en argument """ return pickle.loads(date)[0] def no_mois(date): """renvoie le numéro du mois correspondant à la date donnée en argument """ return pickle.loads(date)[1] def no_annee(date): """renvoie le numéro de l'année correspondant à la date donnée en argument """ return pickle.loads(date)[2]
La fonction nouvelle_date
est la seule fonction qui permet de créer des dates.
Les fonction no_jour
, no_mois
et no_annee
sont les seules fonctions qui permettent de récupérer l'information contenue dans une date.
Vous ne devez à aucun moment utiliser d'autres méthodes pour manipuler les dates elles même. En particuliers, les dates ne sont ni des nombres, ni des tableaux, ni des chaines de caractères.
Exemple :
>>> aujourdhui = nouvelle_date(24, 10, 2016) >>> aujourdhui b'\x80\x03K\x18K\nM\xe0\x07\x87q\x00.' >>> no_jour(aujourdhui) 24 >>> no_mois(aujourdhui) 10 >>> no_annee(aujourdhui) 2016 >>> jamais = nouvelle_date(35, 36, 37) >>> jamais b'\x80\x03K#K$K%\x87q\x00.' >>> no_jour(jamais) 35 >>> no_mois(jamais) 36 >>> no_annee(jamais) 37
Écrivez une procédure affiche_date
qui permet d'afficher (avec la procédure print
) une date donnée en argument.
Par exemple :
>>> affiche_date(aujourdhui) 24-10-2016 >>> affiche-date(jamais) 35-36-37
Remarque : une procédure est une fonction qui ne contient pas l'instruction return
.
L'objectif de cette partie est d'écrire une fonction decale_date
qui prend en paramètres :
n
correspondant à un nombre de jours
et renvoie la date correspondant à une avancée de n
jours dans le temps à partir de la date donnée. Par exemple :
aujourd'hui
, le résultat obtenu sera le 3 novembre 2016
Exemple :
>>> affiche_date(decale_date(aujourdhui, 3)) 27-10-2016 >>> affiche_date(decale_date(aujourdhui, 10)) 3-11-2016 >>> affiche_date(decale_date(nouvelle_date(31, 12, 2016), 1)) 1-1-2017
Pour écrire cette fonction, nous allons commencer par écrire une fonction lendemain
qui prend une date en paramètre et renvoie la date du lendemain.
Nous allons écrire une première version de la fonction lendemain
qui prend une date en paramètre et renvoie la date du lendemain. Dans le cas général, il suffit d'ajouter 1 au n° du jour pour obtenir la date du lendemain. Ainsi par exemple :
>>> affiche_date(lendemain(aujourdhui)) 25-10-2016
Cette règle est correcte pour presque tous les jours de l'année sauf ceux qui correspondent à des fins de mois et fin d'année. Elle est de fait correcte pour 353 jours sur 365.
On aura ainsi :
>>> affiche_date(lendemain(nouvelle_date(31, 11, 2016))) 32-11-2016 >>> affiche_date(lendemain(nouvelle_date(31, 12, 2016))) 32-12-2016
Écrivez la fonction lendemain
telle que définie ci-dessus, qui renverra un résultat correct pour tous les cas sauf les fins de mois et d'année.
Attention : votre fonction lendemain
doit avoir un argument de type date et doit renvoyer un résultat de type date également.
Testez votre fonction.
Nous avions laissé de côté le test de la fonction decale_date
car il fallait au préalable définir lendemain
. C'est maintenant chose faite, même si la fonction lendemain
est encore imparfaite. Il est de fait possible d'écrire une première version de decale_date
.
Écrivez la fonction decale_date
et testez la en prenant des exemples de dates pertinents.
Attention : votre fonction decale_date
doit uniquement utiliser la fonction lendemain
et ne doit pas utiliser les fonctions nouvelle_date
, no_jour
, no_mois
ou no_annee
.
Vous n'aurez normalement pas à modifier votre fonction decale_date
dans la suite du TP.
Dans sa première version, la fonction lendemain
a été définie sans tenir compte des fins de mois et d'année. Nous allons maintenant en écrire une seconde version qui traitera le cas de la fin d'année. Pour cela, nous allons introduire, ici aussi, une fonction qui va nous "faciliter la vie".
Écrivez une fonction fin_annee
qui prend une date en paramètre et teste si cette date correspond à la fin de l'année (c'est-à-dire au 31 décembre).
Modifiez la fonction lendemain
en utilisant fin_annee
et testez cette nouvelle version.
Testez à nouveau la fonction decalage_date
, sans la modifier, pour constater les différences.
Dans sa version actuelle, la fonction lendemain
ne traite pas le cas des fins de mois qui ne sont pas fin d'année. Nous allons maintenant en écrire une troisième et dernière version, qui sera correcte pour toutes les dates. Pour cela, nous allons introduire, encore une fois, une fonction qui va nous "faciliter la vie". Il s'agit de la fonction
fin_de_mois
qui prend une date en paramètre et teste si cette date correspond à une fin de mois.
Exemple :
>>>fin_de_mois(aujourdhui) False >>> fin_de_mois(nouvelle_date(31, 12, 2016)) True >>> fin_de_mois(nouvelle_date(31, 10, 2016)) True >>> fin_de_mois(nouvelle_date(28, 2, 2012)) False >>> fin_de_mois(nouvelle_date(29, 2, 2012)) True
Pour écrire la fonction fin_de_mois
, nous aurons besoin d'une fonction supplémentaire: nb_jours_ds_mois
Cette fonction prend en paramètres :
mois
correspondant à un numéro de mois,
annee
correspondant à un numéro d'année,
et renvoie le nombre de jours dans un mois donné, étant donné une année donnée. Le paramètre annee
est nécessaire du fait des années bissextiles : février n'a en effet pas le même nombre de jours selon que l'année est bissextile ou pas.
Exemple :
>>> nb_jours_ds_mois(5, 2016) 31 >>> nb_jours_ds_mois(2, 2016) 29 >>> nb_jours_ds_mois(2, 2016) 28
Écrivez la fonction est_bissextile
qui teste si une année est bissextile. Pour rappel, une année A est bissextile si A est multiple de 4, mais pas de 100, ou multiple de 400.
Exemple :
>>> est_bissextile(2014) False >>> est_bissextile(2012) True >>> est_bissextile(2000) True >>> est_bissextile(1900) False
Écrivez la fonction nb_jours_ds_mois
en utilisant la fonction est_bissextile
et testez la.
Modifiez la fonction lendemain
en prenant les fins de mois en compte, et testez la sur des exemples de dates pertinents.
Testez la fonction decalage_date
en prenant des exemples de dates pertinents.
Un calendrier perpétuel (voir Wikipedia) est un calendrier qui donne le jour de la semaine (lundi, mardi, mercredi, ...) correspondant à une date donnée. Nous allons, dans cette partie, écrire une fonction calendrier_perpetuel
prenant une date en paramètre et renvoyant une chaîne de caractères correspondant au jour de la semaine de cette date. Nous ne traiterons que les dates appartenant au calendrier grégorien, c'est-à-dire à partir du 20 décembre 1582 en France.
Exemple :
>>> calendrier_perpetuel(nouvelle_date(20, 10, 2014)) "lundi" >>> calendrier_perpetuel(nouvelle_date(8, 10, 2003)) "mercredi" >>> calendrier_perpetuel(nouvelle_date(1, 6, 2014)) "dimanche" >>> calendrier_perpetuel(nouvelle_date(7, 1, 1994)) "vendredi"
C'est M. Moret qui a proposé ce calendrier. Il est composé, dans sa version initiale, de 3 tableaux dans lesquels il faut aller chercher des chiffres en fonction de la date en entrée et faire ensuite des calculs sur ces chiffres. Une version simplifiée a été proposée. Elle consiste à attribuer :
et à faire leur somme. Tous ces nombres sont définis modulo 7 (ex : 5 est équivalent à 12, 19, 26, ...). Le résultat de l'addition, modulo 7 lui aussi, est un nombre compris entre 0 et 6, qui donne le jour de la semaine selon la correspondance suivante :
Nous allons définir, dans ce qui suit, des fonctions permettant de calculer les nombres séculaire, annuel, mensuel et le quantième d'une date donnée. Nous les utiliserons pour définir la fonction calendrier_perpetuel
.
Le « nombre séculaire » est le même pour toutes les années commençant par les deux mêmes chiffres. Par exemple, toutes les années du 21ème siècle (années 2001 à 2099) auront un nombre séculaire égal à 0. C'est également le cas de l'année 2000.
Le tableau suivant donne les nombres séculaires pour chaque siècle :
Il est à noter que ce nombre diminue de deux unités chaque siècle (modulo 7) sauf lorsque les deux premiers chiffres sont un multiple de 4 (1600 à 1699, 2000 à 2099).
Écrivez une fonction nombre_seculaire
qui prend une année en paramètre et renvoie le nombre séculaire associé à cette année.
Exemple :
>>> nombre_seculaire(2014) 0 >>> nombre_seculaire(1996) 1
Vous pourrez introduire des fonctions intermédiaires pour écrire cette fonction, par exemple la fonction siecle
qui prend en paramètre une année A
et renvoie le nombre correspondant au siècle de A
.
Exemple :
>>> siecle(2014) 20 >>> siecle(1996) 19 >>> siecle(1900) 19
La ligne ci-dessous mentionne les années pour lesquelles le nombre annuel est égal à 0. À partir de ces années, le nombre annuel augmente d'une unité chaque année et de deux si l'année est bissextile.
Années dont le nombre annuel est 0 :
..04 ..10 ..21 ..27 ..32 ..38 ..49 ..55 ..60 ..66 ..77 ..83 ..88 ..94
Exemple :
On peut aussi remarquer que le résultat est donné par la formule suivante :
Exemple pour l'année 2010 :
Exemple pour l'année 2016 :
Écrivez une fonction nombre_annuel
qui prend une année en paramètre et renvoie le nombre annuel associé à cette année.
Exemple :
>>> nombre_annuel(2010) 0 >>> nombre_annuel(2016) 1
Vous pourrez introduire des fonctions intermédiaires pour écrire cette fonction, par exemple la fonction an
qui prend en paramètre une année A
et renvoie le nombre correspondant aux 2 derniers chiffres de A
.
Exemple :
>>> an(2014) 14 >>> an(1996) 96 >>> an(1900) 0
Le tableau suivant donne le nombre mensuel pour chaque mois de l'année (cf. Nombre mensuel sur Wikipedia):
mois | nombre mensuel |
---|---|
février (année non bissextile), mars, novembre | 0 |
juin | 1 |
septembre, décembre | 2 |
janvier (année bissextile), avril, juillet | 3 |
janvier (année non bissextile), octobre | 4 |
mai | 5 |
février (année bissextile), aout | 6 |
Exemple : le mois de janvier a un nombre mensuel de 4 en 1995 et de 3 en 1996 (année bissextile).
Ecrire une fonction nombre_mensuel
qui prend en paramètres :
mois
correspondant à un numéro de mois,
annee
correspondant à une année
et qui renvoie le nombre mensuel associé à ces données.
Exemple :
>>> nombre_mensuel(1, 1995) 4 >>> nombre_mensuel(1, 1996) 3
Le quantième correspond au jour d'une date donnée. Ainsi par exemple :
Écrivez une fonction quantieme
qui prend une date en paramètre et renvoie le quantième de la date donnée.
Écrivez la fonction calendrier_perpetuel
qui prend une date en paramètre et renvoie une chaîne de caractères correspondant au jour de la semaine de la date donnée. Vous utiliserez pour cela les fonctions nombre_seculaire
, nombre_annuel
, nombre_mensuel
et quantieme
que vous venez d'écrire.
Il vous faut revenir au début de cette partie pour relire les explications sur le calendrier perpétuel et la manière de calculer le jour de la semaine en utilisant les 4 fonctions définies ci-dessus, ainsi que le tableau de correspondance entre un numéro et un jour de la semaine.
Les vendredis 13 ont toujours hanté l'imaginaire collectif. Pour certains, c'est une date maudite et il convient de rester confiné à la maison ce jour-là si l'on ne veut pas prendre le ciel sur la tête. Pour d'autres, c'est une date porte-bonheur.
Écrivez la fonction vendredi_13
qui prend en paramètres :
annee_initiale
correspondant à une année
annee_finale
correspondant à une année
et calcule le nombre de vendredis 13 qu'il y a entre le 1er janvier de l'année initiale et le 1er janvier de l'année finale. Vous introduirez au préalable une fonction nb_jours
permettant de compter le nombre de jours entre ces 2 dates (vous en aurez besoin pour écrire vendredi_13
Pour rappel, une année comporte 365 jours si elle n'est pas bissextile, 366 sinon.
Exemple :
>>> vendredi_13(2014, 2015) 1 >>> vendredi_13(2010, 2014) 7 >>> vendredi_13(2009, 2010) 3
Utilisez cette fonction pour compter le nombre de vendredis 13 entre 1600 et 2000. Que remarquez-vous ?