Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problèmes de jour dans l'année

Sujet résolu
    11 juin 2023 à 21:04:22

    Bonjour / bonsoir à tous,

    J'ai un petit problème avec ce code, pourtant simple:

    #include <time.h>
    #include <stdio.h>
    #include <stdbool.h>
    
    
    struct param {
    	int dd;
    	int mm;
    	int yy;
    	int repeat;
    };
    
    
    void help(void) {
    	puts("Donne le nom du jour de la date fournie dans le paramètre");
    	puts("Si le second paramètre est donné, calcule quelles sont les autres dates qui ont ce même jour");
    	puts("Le 1er paramètre doit être le jour, le mois et l'année sous la forme j[j]/m[m]/aaaa (obligatoire)");
    	puts("Le 2nd paramètre (facultatif) est le nombre de répétitions souhaitées");
    	puts("Remarque: aucun contrôle n'est effectué sur la validité des paramètres donnés");
    }
    
    
    bool GetParam(struct param *prm, int argc, char *argv[]) {
    	if(argc<2)
    		return(false);
    	if(sscanf(argv[1],"%d/%d/%d", &prm->dd, &prm->mm, &prm->yy)!=3)
    		return(false);
    	if(argc>2)
    		if(sscanf(argv[2],"%d", &prm->repeat)!=1 || prm->repeat<1)
    			return(false);
    	
    	return(true);
    }
    		
    
    int main(int argc,char *argv[]) {
    	struct param prm={0};
    	static char *day_of_week[]={"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"};
    	
    	if(!GetParam(&prm, argc, argv)) {
    		help();
    		return(-1);
    	}
    
    	time_t timestamp;
    	struct tm *tinfo;
    	int searched_day=-1;
    	do {
    		timestamp=time(NULL);
    		tinfo=localtime(&timestamp);
    		tinfo->tm_year=prm.yy-1900;
    		tinfo->tm_mon=prm.mm-1;
    		tinfo->tm_mday=prm.dd;
    		mktime(tinfo);
    		if(searched_day<0)
    			searched_day=tinfo->tm_wday;
    		if(searched_day==tinfo->tm_wday) {
    			printf("Le %02d/%02d/%4d est un %s\n", prm.dd, prm.mm, prm.yy, day_of_week[tinfo->tm_wday]);
    			prm.repeat--;
    		}
    		prm.yy++;
    	} while(prm.repeat>0);
    	
    	return(0);
    }



    Ce qu'il me sort comme réultat n'est pas correct: 

    car en 1968 et 1969, le 11 juin n'est pas un dimanche (tout le reste est correct).

    Pour créer l'exécutable, un petit .bat:

    @echo off
    Echo %1
    gcc -std=c11 -o%1.exe -Wall -Wextra -Wunused -Wswitch-default %2 %1.c

    avec

    Merci d'avance de votre aide.

    Edgar;

    -
    Edité par edgarjacobs 11 juin 2023 à 21:13:41

    • Partager sur Facebook
    • Partager sur Twitter

    On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

      11 juin 2023 à 21:55:29

      Ça alors, chez moi ça marche !

      robun@Ordi:~ > ./zzz 11/06/1967 15
      Le 11/06/1967 est un dimanche
      Le 11/06/1972 est un dimanche
      Le 11/06/1978 est un dimanche
      Le 11/06/1989 est un dimanche
      Le 11/06/1995 est un dimanche
      Le 11/06/2000 est un dimanche
      Le 11/06/2006 est un dimanche
      Le 11/06/2017 est un dimanche
      Le 11/06/2023 est un dimanche
      Le 11/06/2028 est un dimanche
      Le 11/06/2034 est un dimanche
      Le 11/06/2045 est un dimanche
      Le 11/06/2051 est un dimanche
      Le 11/06/2056 est un dimanche
      Le 11/06/2062 est un dimanche
      robun@Ordi:~ > 
      

      Je te suggère d'afficher les valeurs intermédiaires des lignes 49-54.

      -
      Edité par robun 11 juin 2023 à 22:01:20

      • Partager sur Facebook
      • Partager sur Twitter
        11 juin 2023 à 23:15:46

        timestamp de type time_t représente le nombre de secondes écoulé depuis le 1er janvier 1970 or tes dates sont antérieur. Le problème vient peut-être de là ?
        • Partager sur Facebook
        • Partager sur Twitter
        ...
          12 juin 2023 à 0:07:26

          @rouloude: tu as sans doute mis le doigt sur le problème, car testé avec une date dont l'année est >= 1970, le programme donne les bons résultats:

          @robun: comme ça fonctionne chez toi, je suppose que ce sont nos lib qui ne sont pas implémentées de la même manière, mais je ne peux pas implémenter un programme "lib dependant"

          Il ne me reste qu'à trouver un algo pour déterminer convenablement le jour d'une date grégorienne.

          Grandement merci à vous deux.

          Edgar;

          -
          Edité par edgarjacobs 12 juin 2023 à 0:08:18

          • Partager sur Facebook
          • Partager sur Twitter

          On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

            12 juin 2023 à 1:18:30

            @edgarjacobs: as-tu vraiment besoin des secondes ou seulement des jours?


            Tu es chanceux que 2000 soit bissextile, tu aurais de toute façon des problèmes pour 1895 ...


            Ça dépend de ton besoin et de l'efficacité désirée.

            -
            Edité par PierrotLeFou 12 juin 2023 à 1:27:13

            • Partager sur Facebook
            • Partager sur Twitter

            Le Tout est souvent plus grand que la somme de ses parties.

              12 juin 2023 à 1:34:42

              @Pierrot: j'ai juste besoin de savoir que le 11.06.1915 (p.ex.) était un vendredi. Et le nombre d'années séparant  deux dates (à compter de l'année en cours) ne dépassera pas les 120 ans (passé ou futur).

              -
              Edité par edgarjacobs 12 juin 2023 à 1:35:49

              • Partager sur Facebook
              • Partager sur Twitter

              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                12 juin 2023 à 1:54:36

                2023 + 120 = 2143 :)   2023 - 120 = 1903 ... ouf, après 1900 ...


                2100 n'est pas bissextile.

                -

                J'ai essayé une ébauche en pseudo-code +/- en C:

                -

                int difference(date1, date2) {

                    if( ! inferieure(date1, date2)) return - difference(date2, date1)

                    distance = 0

                    if(date1.a < date2.a) {

                        distance += nombre_jours_mois[date1.m] -

                date1.j + 1   // je me place au début du mois suivant

                        for(m = date1.m+1; m <= 12; m++) distance += nombre_jours_mois[m]

                        for(a = date1.a+1; a < date2.a; a++) distance += 365 + bissextile(a)   // 1 si bissextile, 0 sinon


                        date1.j = 1

                        date1.m = 1


                    }


                    for(m = date1.m; m < date2.m; m++) distance += nombre_jours_mois[m]


                    distance += date2.j - date1.j


                   return distance


                }

                -
                Edité par PierrotLeFou 12 juin 2023 à 2:59:30

                • Partager sur Facebook
                • Partager sur Twitter

                Le Tout est souvent plus grand que la somme de ses parties.

                  12 juin 2023 à 11:16:42

                  Un algorithme qu'on trouve un peu partout consiste à calculer le jour julien de la date dont on cherche le jour de la semaine. Ensuite, on fait un modulo 7.

                  Voir par exemple Wikipédia : https://fr.wikipedia.org/wiki/Jour_julien , qui donne des algorithmes.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    12 juin 2023 à 15:18:47

                    Pour valider:


                    https://blogs.anirom.com/joursemaine/index.php


                    Le Krakatoa a explosé le LUNDI 27 août 1883

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Le Tout est souvent plus grand que la somme de ses parties.

                      12 juin 2023 à 23:42:30

                      Re, -

                      Suite à la dernière réponse de robun, et la méthode présentée me paraissant un poil compliquée, j'ai continué mes recherches et ai trouvé cette page sur wikibooks avec des algorithmes, que je n'ai pas tardés à tester. Et fichtre, ça fonctionne:

                      #include <stdio.h>
                      #include <stdbool.h>
                      
                      
                      struct param {
                      	int dd;
                      	int mm;
                      	int yy;
                      	int repeat;
                      };
                      
                      
                      void help(void) {
                      	puts("Donne le nom du jour de la date fournie dans le paramètre");
                      	puts("Si le second paramètre est donné, calcule quelles sont les autres dates qui ont ce même jour");
                      	puts("Le 1er paramètre doit être le jour, le mois et l'année sous la forme j[j]/m[m]/aaaa (obligatoire)");
                      	puts("Le 2nd paramètre (facultatif) est le nombre de répétitions souhaitées");
                      	puts("Remarque: aucun contrôle n'est effectué sur la validité des paramètres donnés");
                      }
                      
                      
                      bool GetParam(struct param *prm, int argc, char *argv[]) {
                      	if(argc<2)
                      		return(false);
                      	if(sscanf(argv[1],"%d/%d/%d", &prm->dd, &prm->mm, &prm->yy)!=3)
                      		return(false);
                      	if(argc>2)
                      		if(sscanf(argv[2],"%d", &prm->repeat)!=1 || prm->repeat<1)
                      			return(false);
                      	
                      	return(true);
                      }
                      		
                      
                      // méthode 1: méthode pour trouver le jour d'une date
                      int main(int argc,char *argv[]) {
                      	struct param prm={0};
                      	static char *day_of_week[]={"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"};
                      	
                      	if(!GetParam(&prm, argc, argv)) {
                      		help();
                      		return(-1);
                      	}
                      
                      	int searched_day=-1;
                      	do {
                      		int wd;
                      		if(prm.mm<3)
                      			wd=((23*prm.mm)/9+prm.dd+4+prm.yy+(prm.yy-1)/4-(prm.yy-1)/100+(prm.yy-1)/400)%7;
                      		else
                      			wd=((23*prm.mm)/9+prm.dd+2+prm.yy+prm.yy/4-prm.yy/100+prm.yy/400)%7;
                      		if(searched_day<0)
                      			searched_day=wd;
                      		if(searched_day==wd) {
                      			printf("Le %02d/%02d/%4d est un %s\n", prm.dd, prm.mm, prm.yy, day_of_week[wd]);
                      			prm.repeat--;
                      		}
                      		prm.yy++;
                      	} while(prm.repeat>0);
                      	
                      	return(0);
                      }
                      
                      
                      // méthode 2: idem, mais pour les années allant de 1583 à 9999
                      int main_2(int argc,char *argv[]) {
                      	struct param prm={0};
                      	static char *day_of_week[]={"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"};
                      	
                      	if(!GetParam(&prm, argc, argv)) {
                      		help();
                      		return(-1);
                      	}
                      
                      	int searched_day=-1;
                      	do {
                      		int c=(14-prm.mm)/12;
                      		int a=prm.yy-c;
                      		int m=prm.mm+12*c-2;
                      		int wd=(prm.dd+a+a/4-a/100+a/400+(31*m)/12)%7;
                      		if(searched_day<0)
                      			searched_day=wd;
                      		if(searched_day==wd) {
                      			printf("Le %02d/%02d/%4d est un %s\n", prm.dd, prm.mm, prm.yy, day_of_week[wd]);
                      			prm.repeat--;
                      		}
                      		prm.yy++;
                      	} while(prm.repeat>0);
                      	
                      	return(0);
                      }
                      

                      Petit test pour le Krakatoa:

                      Le 27/08/1883 est un lundi

                      Et pour le sacre de Napoléon Ier, l'article wikipédia indique qu'il a eu lieu un dimanche, et le programme donne

                      Le 02/12/1804 est un dimanche
                      


                      Encore merci à tous

                      Edit: je ne me suis évidemment pas limité aux deux tests indiqués ici :)

                      -
                      Edité par edgarjacobs 13 juin 2023 à 0:23:54

                      • Partager sur Facebook
                      • Partager sur Twitter

                      On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                      Problèmes de jour dans l'année

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown