IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Calendrier Perpetuel : perfectionnement du code


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Inscrit en
    Décembre 2006
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 205
    Par défaut Calendrier Perpetuel : perfectionnement du code
    Bonjour;
    Dans le cadre de mes études, voici l'énoncé d'un exercice que j'ai à faire:
    Donnez le jour de semaine d'une date comprise entre le

    1er janvier de l'an -2000 au 31 décembre de l'an 4000.

    Gérer si possible les différentents calendriers qui

    ont été utilisés dans l'hitoire de France.

    Voici mon code actuel de calendrier perpétuel en C (de l'an -2000 à 4000): permettant l'affichage du jour de la semaine (lundi, mardi,mercredi...) en fonction de la date, mais il reste perfectible.
    En effet, il y a des jours qui n'existent pas comme les 29 févriers des années non bissextiles qui sont affichées. Je voudrais que ces jours ne soient pas affichées (message d'erreur à la place).
    Je suis en train de plancher sur le code, si vous avez des solutions ou des astuces ou même des remarques quant à l'analyse, n'hésitez pas à me les communiquer.
    Merci.

    Voici le code du programme à perfectionner (élimination des jours n'ayant jamais existé comme les 29 févriers des années non bissextiles):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
     
    #include <stdio.h>
    #include <stdlib.h>
     
    int ansup (int an)
    {
    	int an_bis, an_nbis;
    	an_bis = an_nbis = 0;
     
    	while (an >= 2003)
    	 {
    	 	if ( an%4==0 && an%100!=0 || an%400==0 )
    			an_bis+=1;
    		else
    			an_nbis+=1;
    		an--;
    	}
     
      		return(an_bis * 366  + an_nbis * 365);  /* c'est le nombre de jours entre le 01/01/2003 et le 01/01 de l'année rentrée */
    }
     
    int aninf (int an)
    {
    	int an_bis, an_nbis;
    	an_bis = an_nbis = 0;
     
    	while (an < 2003)
    	{
    		if (an%4 == 0 && an%100 !=0 || an%400 == 0)
    			an_bis+=1;
    		else
    			an_nbis+=1;
    		an++;
    	}
     	return(an_bis * 366 + an_nbis * 365); /* c'est le nombre de jours entre le 01/01 de l'année rentrée et le 01/01/2003 */
    }
     
    int nb_jr (int mois, int an) /* calcul du nombre de jours passés en fonction de l'année (bissextile ou non) et du mois rentrés */
    {
    	int bissextile[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
    	int n_bissextile[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    	int som = 0;
     
    	if ( an%4==0 && an%100!=0 || an%400==0 )
    	{
    		while (mois>0)
    		{
    			som = som + bissextile[mois-1];
    			mois--;
    		}
    	}
    	else
    	{
    		while (mois>0)
    		{
    			som = som + n_bissextile[mois-1];
    			mois--;
    		}
    	}
    	return som;
    }
     
    int main ()
    {
    	int ans, ms, jr, jrs;
    	char *jouri[7] = {"mardi", "lundi", "dimanche", "samedi", "vendredi", "jeudi", "mercredi"};
    	char *jours[7] = {"mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche", "lundi"};
     
     	printf("rentrer une annee (entre -2000 et 4000) :");
    	scanf("%d",&ans);
    	printf("\n");
    	printf("rentrer un mois (entre 1 et 12) :");
    	scanf("%d",&ms);
    	printf("\n");
        printf("rentrer un jour (entre 1 et 31) :");
    	scanf("%d",&jr);
    	printf("\n");
     
        if ((ans >= -2000) && (ans <=4000) && (ms >=1) && (ms<=12) && (jr >=1) && (jr <= 31))
        {
    	    if(ans < 2003)   /*si l'année saisie est inférieure à 2003*/
    	    {
      		    printf("\nLe (%d/%d/%d) est un %s.\n\n", jr, ms, ans, jouri[(aninf (ans) - nb_jr (ms, ans) - jr)%7]);
    	    }
    	    else if (ans >= 2003) /*si l'année saisie est sup ou égale à 2003*/
    	    {
    		    if ( ans%4==0 && ans%100!=0 || ans%400==0 )
    			    jrs = 366 - nb_jr (ms, ans);
    		    else
    			    jrs = 365 - nb_jr (ms, ans); /*jrs est le nombre de jours restant de l'année rentrée*/
     
                printf("\nLe (%d/%d/%d) est un %s.\n\n", jr, ms, ans, jours[(ansup (ans) - jrs + jr)%7]);
    	    }
        }
        else 
        {
        printf ("\n");
        printf ("Erreur de saisie.\n");
        printf ("Saisir obligatoirement une date dont: \n");
        printf ("L'annee varie de -2000 a 4000 inclus.\n");
        printf ("Le mois varie de 1 a 12 inlus.\n");
        printf ("Le jour varie de 1 a 31 inclus.");
        }
    	return 0;
    }

  2. #2
    Membre expérimenté
    Inscrit en
    Décembre 2003
    Messages
    272
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 272
    Par défaut
    Citation Envoyé par cirtey
    Gérer si possible les différentents calendriers qui ont été utilisés dans l'hitoire de France.
    Je ne me rappelle plus trop quel calendrier était utilisé avant -45 (12 mois de 30 jours et 5 jours hors de l'année), mais jusqu'en 1582 c'était le calendrier julien : toutes les années multiples de 4 sont bisextiles.
    10 jours ont disparus lors du changement de calendrier, on est passé du jeudi 4 octobre 1582 au vendredi 15 octobre (en France, dans d'autres pays le changement de calendrier s'est fait plus tard).
    Il faut également noter qu'il n'y a pas d'an 0 dans le calendrier.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if ( an%4==0 && an%100!=0 || an%400==0 )
    Avec des parenthèses ce sera mieux (2 fois dans ton code).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if(ans < 2003)   /*si l'année saisie est inférieure à 2003*/
        {
        ...
        }
    else if (ans >= 2003) /*si l'année saisie est sup ou égale à 2003*/
        {
        ...
        }
    Le second "if" est superflu puisque c'est la condition contraire du premier.

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    La regle, pour les années bisextiles est:
    une année est bisextile si son nombre est divisible par quatre, sauf s'il est divisible par 100, sauf s'il est divisible par 400 (comprendre: elle l'est de nouveau, bien que divisible par 100 si elle est divisible par 400)...
    Il devient donc facile de créer une petite fonction qui s'occupe de calculer cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    /* @in: année à tester
       @out: 0 si l'annee n'est pas bisextile, 1 si elle l'est
    */
     
    int Bisextile(int annee)
    {
        if(annee%4==0)
        {
    /* si l'année est divisible par 4, il faut tester si elle l'est par 100 */
            if(annee%100==0)
            {
    /* si l'année est divisible par 100, il faut tester si elle l'est par 400*/
                 if(annee%400==0)
                     return 1;
    /* on n'arrive ici que si l'année n'est pas divisible par 400 (mais qu'elle
       l'est par 100) ;) */
                 return 0;
            }
    /* on n'arrive ici que si l'année n'est pas divisible par 100 (mais qu'elle
       l'est par 4) ;)*/
            return 1;
        }
    /* si l'année n'est pas divisible par 4, c'est d'office non */
        return 0;
    }
    Avec cette fonction prete, tu pourrait tres bien envisager de travailler selon le principe de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    /* le nombre de jours des douze mois de l'année (fevrier est à 0, car il
       faut le déterminer avec bisextile ;) */
    int mois[]={31,0,31,30,31,30,31,31,30,31,30,31};
    int annee;
    /* tout ce qu'il faut pour récupérer l'année */
     
    mois[1]=(Bissextile(annee)==1? 29:28;)
    /* ou, si  tu préfère */
    if(Bissextile(annee)==1)
        mois[1]=29;
    else
        mois[1]=28;
    /* la suite du travail ;) */
    /* si tu préfère avoir le nombre de jours de l'année, ca peut, apres avoir
       déterminé le nombre de jours de fevrier, se faire sous la forme de */
    int nb_jours=0;
    int i;
    for(i=0;i<12;i++)
        nb_jours+=mois[i];
    Pour arriver à déterminer le jour de la semaine d'une date bien précise, il ne te reste plus qu'à connaitre une date de référence
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 397
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 397
    Par défaut
    Je crois bien avoir lu dans une revue (Pour la Science, Sciences&Avenir ou Science&Vie Junior) que pour être exact, il faudrait aussi rajouter "sauf s'il est divisible par 4000", mais que:
    • À l'époque de l'écriture du magazine, ce n'était pas encore dans le calendrier officiel
    • On a le temps.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre très actif
    Inscrit en
    Décembre 2006
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 205
    Par défaut
    Merci pour vos réponses.
    Effectivement; les jours à éliminer sont:
    1- les 29 févriers des années non bissextiles
    2- l'année 0
    3- le 4, 5, 6, 6, 8, 9, 10, 11, 12, 13, 14, 15 octobre 1582 : le décalage grégorien qui supprima dix jours du calendrier, entre le 4 octobre 1582 et le 15 octobre 1582 pour les pays ayant immédiatement suivi Rome, ce qui permit de fixer de nouveau l’équinoxe de printemps le 21 mars, comme ce fut le cas au début de l’ère chrétienne

    Les cas 2 et 3 semblent relativement faciles à supprimer, il suffit de rajouter des conditions à la ligne 80 du code : if ((ans >= -2000) && (ans <=4000) && (ms >=1) && (ms<=12) && (jr >=1) && (jr <= 31)).
    Par contre les 29 févriers sont plus compliqués à supprimer.
    J'ai pensé à tranformer les 3 conditions en booléens puis les insérer dans le if de la ligne 80 du code. Par ex mettre en place la fonction calcul année non bissextile + jour 29 + mois 2 en true (1), me semble être une solution pour le cas 1. Qu'en pensez-vous? Est-ce faisable?

  6. #6
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Pourquoi ne pas faire simplement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int estbissextile(int annee)
     {return !(annee%4) && annee%100 || !(annee%400);}
     
     
    int main(void)
     {
     ...
     if (ms==2 && jr==29 && !estbissextile(ans))
      {
      /*Erreur*/
      ...
      }
     ...
     }
    ?

  7. #7
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par Médinoc
    Je crois bien avoir lu dans une revue (Pour la Science, Sciences&Avenir ou Science&Vie Junior) que pour être exact, il faudrait aussi rajouter "sauf s'il est divisible par 4000", mais que:
    • À l'époque de l'écriture du magazine, ce n'était pas encore dans le calendrier officiel
    • On a le temps.
    Faux. (Pour une simple raison, on est dans l'ordre de grandeur de variation de l'annee qui est corrigee tous les six mois par l'ajout/le retrait de seconde -- voir difference entre temps UTC et temps TAI).

  8. #8
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    La technique habituelle de gestion de date sur une longue periode avec different calendrier est de prevoir des conversions de chaque calendrier vers le jour julien et inversement.

  9. #9
    Membre très actif
    Inscrit en
    Décembre 2006
    Messages
    205
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 205
    Par défaut
    Je vais finalement garder ma dernière version, je n'ai pas le temps de tout refaire à 0, j'ai d'autres projets en cours.
    Merci beaucoup à tous ceux qui ont contribué à ce thread.
    A+

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Heu...

    As tu au moins pris la peine de jeter une oeil au code que j'ai fournis, qui fonctionne parfaitement, et dans lequel il ne manque que l'inclusion des fichiers d'entetes, et peut etre l'une ou l'autre fonction
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Réponses: 58
    Dernier message: 27/04/2015, 14h09
  2. [XL-2002] RP et Feriés dans Calendrier perpetuel
    Par freddy80 dans le forum Excel
    Réponses: 3
    Dernier message: 22/04/2014, 09h35
  3. Calendrier - Extraire un code
    Par NooD dans le forum Access
    Réponses: 4
    Dernier message: 13/07/2006, 14h56
  4. Réaliser calendrier perpetuel avec EXEL
    Par Perdus dans le forum Autres Logiciels
    Réponses: 2
    Dernier message: 20/10/2005, 08h05
  5. [toFAQ]calendrier perpetuel
    Par philippe_jasmin dans le forum C
    Réponses: 17
    Dernier message: 22/04/2003, 19h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo