Manipulation de dates [dt06] - Exercice
Karine Zampieri, Stéphane Rivière
Unisciel algoprog Version 21 mai 2018
Table des matières
1 Nombre de jours des mois d’une année 3
1.1 Fonction bissextile (test de bissextilité) . . . . . . . . . . . . . . . . . . . 3
1.2 Fonction njours (nombre de jours d’un mois et année) . . . . . . . . . . . 4
1.3 Application : Nombre de jours des mois d’une année . . . . . . . . . . . . 5
2 Saisie vérifiée et affichage d’une date 5
2.1 Type DateJMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Fonction datumDT (validité d’une date) . . . . . . . . . . . . . . . . . . 6
2.3 Procédure saisirDT (saisie d’une date) . . . . . . . . . . . . . . . . . . . 7
2.4 Fonction dateEnChaine (date en chaı̂ne) . . . . . . . . . . . . . . . . . . 7
2.5 Application : saisie vérifiée et affichage . . . . . . . . . . . . . . . . . . . 9
3 Jour de semaine d’une date 9
3.1 Fonction gregorienneDT (test date grégorienne) . . . . . . . . . . . . . . 9
3.2 Fonction jsemaineDT (jour de la semaine) . . . . . . . . . . . . . . . . . 10
3.3 Fonction nomJSemaine (jour de semaine en toutes lettres) . . . . . . . . 12
3.4 Application : jour de semaine . . . . . . . . . . . . . . . . . . . . . . . . 12
3.5 Procédure saisirGregDT (saisie d’une date) . . . . . . . . . . . . . . . . . 13
3.6 Application : jour de semaine de votre naissance . . . . . . . . . . . . . . 14
4 Références générales 14
Java - Manipulation de dates (Solution)
Mots-Clés Dates et Heures
Requis Axiomatique impérative (sauf Fichiers)
Difficulté • ◦ ◦ (1 h 30)
Objectif
Le premier exercice calcule le nombre de jours des mois d’une année, le deuxième effectue
1
Unisciel algoprog – Manipulation de dates [dt06] 2
la saisie vérifiée et affichage d’une date et le troisième détermine le jour de semaine d’une
date.
Unisciel algoprog – Manipulation de dates [dt06] 3
1 Nombre de jours des mois d’une année
1.1 Fonction bissextile (test de bissextilité)
Définition
Soit une année postérieure à 1582 (début du calendrier grégorien).
Elle est bissextile si et seulement si son millésime est :
• Divisible par 4 mais non divisible par 100.
• Ou divisible par 400.
Exemples
• 1986 : non (non divisible par 4)
• 1988 : oui (divisible par 4 et non divisible par 100)
• 1900 : non (divisible par 4 et par 100)
• 2000 : oui (divisible par 400)
Écrivez une fonction bissextile(an) qui teste et renvoie Vrai si le millésime d’une année
an (entier supérieur à 1582) est bissextile, Faux sinon.
Solution Paramètres
Entrants : Un entier an
Résultat de la fonction : Un booléen
Solution simple
En tant que prédicat (fonction booléenne), le corps de la fonction est simplement consti-
tué de l’expression booléenne qui traduit l’énoncé.
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Prédicat d’année bissextile
@param[in] an - millésime d’une annee > DEBUTGREGCALENDRIER=1582
@return vrai si an est bissextile
*/
public static boolean bissextile(int an)
{
return (an % 4 == 0 && !(an % 100 == 0)) || (an % 400 == 0);
}
Unisciel algoprog – Manipulation de dates [dt06] 4
1.2 Fonction njours (nombre de jours d’un mois et année)
Propriété
Pour les années postérieures à 1582 (année du calendrier Grégorien) :
• Les mois numéros 4, 6, 9 et 11 ont 30 jours.
• Le mois numéro 2 a 29 jours si l’année est bissextile, 28 sinon.
• Sinon c’est 31 jours pour tous les autres mois 1, 3, 5, 7, 8, 10 et 12.
Écrivez une fonction njours(mm,an) qui calcule et renvoie le nombre de jours d’un numéro
de mois mm (entier compris entre 1 (pour janvier) et 12 (pour décembre)) d’une année an
(entier supérieur à 1582).
Aide méthodologique
Préférez une structure Selon.
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Nombre de jour d’un mois et année
@param[in] mm - numéro de mois dans [1..12]
@param[in] an - millésime d’une année > DEBUTGREGCALENDRIER
@return le nombre de jours de (mm,an)
*/
public static int njours(int mm, int an)
{
int rs = 0;
switch (mm)
{
case 4: case 6: case 9: case 11:
rs = 30;
break;
case 2:
rs = (bissextile(an) ? 29 : 28);
break;
default:
rs = 31;
}
return rs;
}
Unisciel algoprog – Manipulation de dates [dt06] 5
1.3 Application : Nombre de jours des mois d’une année
Écrivez une procédure test_njours qui saisit le millésime d’une année puis qui affiche le
nombre de jours pour chacun des numéros de mois de l’année.
Testez. Exemple d’exécution :
Millesime de l’annee? 2000
31 29 31 30 31 30 31 31 30 31 30 31
Validez votre procédure avec la solution.
Solution Java @[pgdates.java]
/**
@test
*/
public static void test_njours()
{
Scanner input = new Scanner(System.in);
int annee;
System.out.print("Millesime de l’annee? ");
annee = input.nextInt();
for (int mois = 1; mois <= 12; ++mois)
{
System.out.print(UtilsDT.njours(mois,annee) + " ");
}
System.out.println();
}
2 Saisie vérifiée et affichage d’une date
2.1 Type DateJMA
Définissez le type DateJMA sous la forme d’un triplet d’entiers contenant : le numéro de
jour, le numéro de mois et le millésime de l’année.
Validez votre définition avec la solution.
Solution Java @[UtilsDT.java]
/**
Type Date
*/
public static class DateJMA
{
/// numéro de jour
Unisciel algoprog – Manipulation de dates [dt06] 6
public int jr;
/// numéro de mois
public int mm;
/// millésime de l’année
public int an;
}
2.2 Fonction datumDT (validité d’une date)
Définition
Un triplet d’entiers (j, m, a) est une date valide si :
• Le millésime de l’année a est un entier positif.
• Le numéro du mois m est compris entre 1 et 12.
• Le numéro du jour j est compris entre 1 et le nombre de jours du mois m de
l’année a.
Exemples
Les 30/4/1950 et 29/2/1996 sont des dates valides.
Mais ne sont pas valides :
• Le 29/2/1987 (le jour est supérieur au dernier jour du mois de l’année considérée)
• Le 25/13/2000 (le mois n’est pas un numéro valide)
• Le 5/5/-2000 (l’année n’est pas positive)
Écrivez une fonction datumDT(dt) qui teste et renvoie Vrai si et seulement si une DateJMA dt
représente une date valide, Faux sinon.
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Prédicat de DateJMA
@param[in] dt - une DateJMA
@return Vrai si dt est une date valide, Faux sinon
*/
public static boolean datumDT(final DateJMA dt)
{
return (dt.an >= 0) && (1 <= dt.mm && dt.mm <= 12) && (1 <= dt.jr && dt.jr <=
njours(dt.mm,dt.an));
}
Unisciel algoprog – Manipulation de dates [dt06] 7
2.3 Procédure saisirDT (saisie d’une date)
Écrivez une procédure saisirDT(dt) qui saisit une DateJMA dans dt. La date doit être
demandée tant qu’elle n’est pas valide. Affichez l’invite :
jr/mm/an?
Validez votre procédure avec la solution.
Solution Java @[UtilsDT.java]
/**
Saisie contrainte d’une date
@param[out] dt - une DateJMA
*/
public static void saisirDT(DateJMA dt)
{
Scanner input = new Scanner(System.in);
dt.jr = 0;
dt.mm = 0;
dt.an = 0;
char c;
while (!datumDT(dt))
{
System.out.print("jr/mm/an? ");
dt.jr = input.nextInt();
c = input.next().charAt(0);
dt.mm = input.nextInt();
c = input.next().charAt(0);
dt.an = input.nextInt();
}
}
2.4 Fonction dateEnChaine (date en chaı̂ne)
Traduction dateEnChaine
Pour traduire un triplet d’entiers (jour, mois, année) en chaı̂ne de caractères, une stratégie
consiste à traduire le numéro de jour j, le numéro de mois m et l’année a en chaı̂ne.
Exemples :
dateEnChaine(12,3,6) ==> "12/3/06"
dateEnChaine(12,3,2006) ==> "12/3/2006"
Écrivez une fonction dateEnChaine(dt) qui calcule et renvoie la traduction sous forme d’une
chaı̂ne "[jr]/[mm]/[an]" (où [x] désigne le contenu de x) d’une DateJMA dt.
Aide méthodologique
Distinguez le cas où l’année an est supérieure à 100 pour tenir compte du zéro significatif
dans les dizaines.
Unisciel algoprog – Manipulation de dates [dt06] 8
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Conversion d’un chiffre en Ascii
@param[in] n - un entier dans [0..9]
@return la conversion d’un chiffre en Ascii
*/
public static char cvchiffre(int n)
{
return (char)(n + (int)’0’);
}
/**
Traduction d’un nombre sur deux chiffres en chaine
@param[in] n - un entier dans [0..99]
@param[in] b - si vrai, traduction du zéro
@return le nombre en chaine
*/
public static String nnEnChaine(int n, boolean b)
{
String rs = "";
int dizaine = (n / 10) % 10;
if (dizaine != 0 || b)
{
rs += cvchiffre(dizaine);
}
rs += cvchiffre(n % 10);
return rs;
}
/**
Traduction d’une DateJMA en chaine
@param[in] dt - une DateJMA
@return la date dt sous forme de chaine
*/
public static String dateEnChaine(final DateJMA dt)
{
// Traduction du numéro de jour
String rs = nnEnChaine(dt.jr,false) + "/";
// Traduction du numéro de mois
rs += nnEnChaine(dt.mm,false) + "/";
// Traduction de l’année
if (dt.an >= 100)
{
rs += nnEnChaine(dt.an / 100,true);
}
rs += nnEnChaine(dt.an % 100,true);
return rs;
}
Unisciel algoprog – Manipulation de dates [dt06] 9
2.5 Application : saisie vérifiée et affichage
Écrivez une procédure test_datum qui réalise la saisie d’une DateJMA puis qui la traduit et
l’affiche.
Testez. Exemples d’exécution :
jr/mm/an? 18/1/1909
==> 18/1/1909
jr/mm/an? 18/13/1994
jr/mm/an? 31/11/1994
jr/mm/an? 29/2/1994
jr/mm/an? 28/2/94
==> 28/2/94
Commentaires
Les dates 18/1/1909 et 29/2/1996 sont valides car l’année, le mois et le jour sont valides.
La date 18/13/1994 n’est pas valide car le mois n’est pas valide. Les dates 31/11/1994
et 29/2/1994 ne sont pas valides, le jour étant supérieur au nombre de jour du mois de
l’année considérée.
Validez votre procédure avec la solution.
Solution Java @[pgdates.java]
/**
@test
*/
public static void test_datum()
{
UtilsDT.DateJMA dt = new UtilsDT.DateJMA();
UtilsDT.saisirDT(dt);
System.out.println("==> " + UtilsDT.dateEnChaine(dt));
}
3 Jour de semaine d’une date
3.1 Fonction gregorienneDT (test date grégorienne)
Définition
Grégoire XIII a imposé sa réforme du calendrier Grégorien le jeudi 4 octobre 1582
qui fut alors suivi du vendredi 15 octobre 1582 (nous avons effectivement « sauté » dix
jours).
Unisciel algoprog – Manipulation de dates [dt06] 10
Écrivez une fonction gregorienneDT(dt) qui teste et renvoie Vrai si une DateJMA dt est pos-
térieure à la réforme du calendrier du jeudi 4 octobre 1582, Faux sinon.
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Début calendrier grégorien
*/
final static int DEBUTGREGCALENDRIER = 1582;
/**
Prédicat de DateJMA grégorienne
@param[in] dt - une DateJMA
@return Vrai si dt est grégorienne
*/
public static boolean gregorienneDT(final DateJMA dt)
{
boolean nonb1 = (dt.an < DEBUTGREGCALENDRIER);
boolean nonb2 = (dt.an == DEBUTGREGCALENDRIER && (dt.mm < 10 || (dt.mm == 10 && dt.jr
< 5)));
return !(nonb1 || nonb2);
}
3.2 Fonction jsemaineDT (jour de la semaine)
Ce problème détermine le numéro du jour de la semaine (c.-à-d. 0=dimanche, 1=lundi,
etc.) d’une date (jour, mois, année).
Définition
La formule de Zeller (énoncée ci-après) permet de calculer le jour de semaine d’une date
du calendrier Grégorien 1 . Pour l’utiliser, il faut décaler la date de deux mois. L’année
de Zeller commence au mois de mars. Ainsi la date grégorienne 7/2/2010 doit être
transformée en 7/12/2009 pour Zeller, et la date grégorienne 5/4/2010 en 5/2/2010
pour Zeller.
Formule de Zeller
Soit d un jour de la semaine dans [0..6] avec d = 0 pour le dimanche.
Soient :
• m : le numéro du mois dans l’année de Zeller
• a : le numéro de l’année de Zeller
• j : le numéro du jour dans le mois de Zeller
1. Le calendrier Grégorien fut adopté en France, Italie, Espagne et Portugal le 15/10/1582, en Pologne
en 1587, en Grande-Bretagne en 1753, au Japon en 1911, en Chine en 1917, en URSS et en Grèce en
1926.
Unisciel algoprog – Manipulation de dates [dt06] 11
• n = a mod 100 : le numéro de l’année dans le siècle de Zeller
• s : le numéro du siècle de Zeller
La formule de Zeller est
d = f mod 7
avec
f = j + n + 5s + n div 4 + s div 4 + (13m − 1) div 5
où l’opérateur div désigne la division entière et l’opérateur mod le reste de la division
entière.
Remarque
Grégoire XIII a imposé la réforme du calendrier le jeudi 4 octobre 1582 qui fut alors
suivi du vendredi 15 octobre 1582. Avant ce changement, la formule de Zeller fonc-
tionne en ajoutant 3 à f .
Écrivez une fonction jsemaineDT(dt) qui calcule et renvoie le numéro de jour de la semaine
d’une DateJMA dt en appliquant la formule de Zeller.
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Jour de la semaine par la Formule de Zeller
@param[in] dt - une DateJMA
@return le jour de semaine de dt
*/
public static int jsemaineDT(final DateJMA dt)
{
int m, a;
if (dt.mm >= 3)
{
m = dt.mm - 2;
a = dt.an;
}
else
{
m = dt.mm + 10;
a = dt.an - 1;
}
int s = a / 100;
int n = a % 100;
int f = dt.jr + n + 5 * s + n / 4 + s / 4 + (13 * m - 1) / 5;
if (!gregorienneDT(dt))
{
f += 3;
Unisciel algoprog – Manipulation de dates [dt06] 12
}
return (f % 7);
}
3.3 Fonction nomJSemaine (jour de semaine en toutes lettres)
Écrivez une fonction nomJSemaine(jsem) qui calcule et renvoie le nom d’un numéro de jour
de semaine jsem en toutes lettres, dimanche étant le numéro 0 et samedi le numéro 6.
L’entier jsem est supposé compris dans [0..6].
Validez votre fonction avec la solution.
Solution Java @[UtilsDT.java]
/**
Noms des jours
*/
final static String[] NOMSJOURS =
{"Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"};
/**
Nom d’un jour de semaine en toutes lettres
@param[in] jsem - numéro jour de semaine dans (0=dimanche,...,6=samedi)
@return le nom de jsem en toutes lettres
*/
public static String nomJSemaine(int jsem)
{
return NOMSJOURS[jsem];
}
3.4 Application : jour de semaine
Écrivez une procédure test_jsemaine qui saisit une DateJMA puis qui calcule et affiche le
nom et le numéro de jour de semaine correspondant.
Testez. Exemples d’exécution :
jr/mm/an? 4/10/1582
==> Jeudi (4)
jr/mm/an? 1/1/2003
==> Mercredi (3)
jr/mm/an? 14/7/1789
==> Mardi (2)
jr/mm/an? 5/7/1968
==> Vendredi (5)
Unisciel algoprog – Manipulation de dates [dt06] 13
Validez votre procédure avec la solution.
Solution Java @[pgdates.java]
/**
@test
*/
public static void test_jsemaine()
{
UtilsDT.DateJMA dt = new UtilsDT.DateJMA();
UtilsDT.saisirDT(dt);
int jsem = UtilsDT.jsemaineDT(dt);
System.out.println("==> " + UtilsDT.nomJSemaine(jsem) + " (" + jsem + ")");
}
3.5 Procédure saisirGregDT (saisie d’une date)
Écrivez une procédure saisirGregDT(dt) qui saisit une DateJMA dans dt. La date doit être
demandée tant qu’elle n’est pas une date grégorienne valide. Affichez les invites :
Millesime de l’annee?
Numero du mois?
Numero du jour?
Validez votre procédure avec la solution.
Solution Java @[UtilsDT.java]
/**
Saisie contrainte d’une date
@param[out] dt - une DateJMA
*/
public static void saisirGregDT(DateJMA dt)
{
Scanner input = new Scanner(System.in);
dt.jr = 0;
dt.mm = 0;
dt.an = 0;
while (!(datumDT(dt) && gregorienneDT(dt)))
{
System.out.print("Millesime de l’annee? ");
dt.an = input.nextInt();
System.out.print("Numero du mois? ");
dt.mm = input.nextInt();
System.out.print("Numero du jour? ");
dt.jr = input.nextInt();
}
}
Unisciel algoprog – Manipulation de dates [dt06] 14
3.6 Application : jour de semaine de votre naissance
Écrivez une procédure test_jsemnaiss qui saisit une DateJMA grégorienne puis qui affiche
la date ainsi que le nom du jour de semaine.
Testez la procédure avec votre ou des dates de naissance.
Exemple d’exécution :
Millesime de l’annee? 2000
Numero du mois? 1
Numero du jour? 1
==> 1/1/2000 est un Samedi
Validez votre procédure avec la solution.
Solution Java @[pgdates.java]
/**
@test
*/
public static void test_jsemnaiss()
{
UtilsDT.DateJMA dt = new UtilsDT.DateJMA();
UtilsDT.saisirGregDT(dt);
int jsem = UtilsDT.jsemaineDT(dt);
System.out.println("==> " + UtilsDT.dateEnChaine(dt) + " est un " +
UtilsDT.nomJSemaine(jsem));
}
4 Références générales
Comprend