Anzahl der vergangenen Werktage
-
Hallo Gemeinde,
ich soll ein Codemodul schreiben, welches die Anzahl der Tage zwischen zwei Datumsangaben ermittelt. Dabei habe ich zwei Probleme. Die üblichen Datumsfunktionen funktionieren ja nur zurück bis zum 1.1.1970, die Funktion soll aber sehr viel weiter zurückreichen. Noch schlimmer ist, dass ich nur Werktage zählen darf. Ich hab echt keinen Plan, wie ich das anstellen soll. Ich habe die Manpages schon vor- und rückwärts durchgelesen, aber irgendwie finde ich dort nichts, was mich meinem Ziel auch nur ein Stück weit näher bringt. So ungewöhnlich ist das Problem doch gar nicht, da muß es doch was geben? Habt ihr vielleicht eine Idee?
Danke,
Sophie
-
Vielleicht mal unter "Quelltext gregorianischer Kalender" suchen?
MfG
-
Meinst Du mit nur Werktage Mo-Fr oder werden Feiertage extra abgezogen?
-
Datumsdifferenz:
#include <stdio.h> #include <stdlib.h> typedef unsigned long date_t; #define is_leap(y) ((y)%4==0 && ((y)%100!=0 || (y)%400==0)) /* Encode date (> 0000-03-01) to date_t y: >=0 m: 0...11 d: 0...[27,28,29,30] (depends on length of month) */ date_t foo(int y, int m, int d) { static unsigned const moff[12] = /* Month: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec */ /* Days: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; date_t ret; /* calculate plain offset */ ret = (date_t)y*365 + moff[m] + d; /* add leap days */ if( m<2 ) y-=1; return ret + (date_t)y/4 - y/100 + y/400 - 59; } void bar(int *py, int *pm, int *pd, date_t d) { register unsigned x; unsigned y, m; static unsigned char const tt[5] = { 0, 1, 2, 3, 3}; static unsigned const moff[13]= /* Month: Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Jan, Feb - */ /* Days: 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29, - */ { 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 366 }; x=d/146097; d-=x*146097; y =x*400; /* 400 years (Epoch) */ x=tt[d/36524]; d-=x*36524; y+=x*100; /* 100 years of ^(Century) */ x=d/1461; d-=x*1461; y+=x*4; /* 4 years of ^ (Quad) */ x=tt[d/365]; d-=x*365; y+=x; /* 1 year of ^ (Year) */ if(moff[m=(d>>5)+1] > d) m-=1; /* Month */ d-=moff[m]; if(m>9) { m-=10; y+=1;} else m+=2; *py = y; *pm = m; *pd = d; /* Deliver */ } /* Start debugging stuff */ int check( date_t (*foo)(int,int,int), void (*bar)(int*, int*, int*, date_t) ) { int y=0, m=2, d=0, dm; /* We start at 0000-03-01 */ date_t r=0; int y1, m1, d1; /* Targets */ static int const mdays[12]= /* Month: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, - */ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; do { /* year */ do { /* month */ dm=mdays[m]; if(m==1 && is_leap(y)) dm+=1; do { /* day */ if(r!=foo(y,m,d)) { printf("encode error: %04d-%02d-%02d:date2num: %lu - r:%lu\n", y, m, d, foo(y,m,d), r); return 1; } bar(&y1, &m1, &d1, r); if(y1!=y || m1!=m || d1!=d) { printf("decode error: %04d-%02d-%02d (r=%lu) -> %04d-%02d-%02d\n", y, m, d, r, y1, m1, d1); return 1; } r+=1; } while((++d)<dm); d=0; } while((++m)<12); m=0; } while((++y)<6000); return 0; } int main(void) { int i; for(i=10; i--;) check(foo, bar); printf("foo/bar - done\n"); system("pause"); return 0; }
Kommste damit klar? Die Funktion foo() liefert fortlaufende Zahlen für fortlaufende Daten. Die Funktion bar() zerdröselt die Zahl wieder in Tag, Monat und Jahr. Nachdem jede Woche nun mal 7 Tage hat, solltest Du die WE leicht erschlagen können. Wenn Du allerdings auch Feiertage berücksichtigen musst, dann wird's haarig und zumindest unser lieber Herr Gauß ist gefragt. Die Feiertage orientieren sich nämlich an festen Daten, dem Osterdatum oder dem Kirchenjahr. Erschwerend kommt noch hinzu, dass die Feiertagsregelungen in verschiedenen Ländern unterschiedlich ist und sich im Lauf der Zeit auch so einiges geändert hat. Das gibt ne ganz schöne Pfriemelei hin, ist zwar nicht sonderlich kompliziert, wird aber ne Fleissaufgabe. Code die Feiertage aber keinesfalls hart rein, sondern lies die Definitionen aus nem Konfigurationsfile! Du willst den Krempel ja nicht nur deshalb neu compilieren, weil sich irgendwas geändert hat.
-
copied & pasted von da: http://www.spotlight-wissen.de/lisp/pages/messages/accc-1112504258-10908
-
Nö, ich bin der Autor von dem Ding und kann's notfalls auch erklären, wie das funzt.
-
Ich habe mir zwei allgemeine Funktionen geschrieben:
- Eine, die eine gültige Datumseingabe erzwingt
- Eine, die Datumsangaben und Gesamttage umrechnen (diese Funktion hatte ich eigentlich geschrieben, um damit Einträge nach dem Datum zu sortieren)Ich habs beides daraus mal so ein Programm geschrieben.
Bin mir nicht sicher, ob das mit den Werktagen so stimmt:/* NAME: datum.c FUNKTION: Berechnet die Differenz in Werktagen zwischen zwei Datumsangaben AUTOR: Simonek HINWEIS: Min. 01.01.0000, Max. 31.12.9999 Das Programm kann noch Fehler enthalten... */ // INCLUDE-DATEIEN #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> // DEFINIERUNGEN #define NEIN 0 #define JA 1 // FUNKTIONS-PROTOTYPEN char *datum_eingeben(void); // ERZWINGT EINE GÜLTIGE DATUMSEINGABE IM FORMAT XX.XX.XXXX unsigned long datum_umwandeln(char str_datum[]); // WANDELT DATUM IN TAGE UM int main(void) { char puffer[11]; long gesamt_anf, gesamt_end; // Gesamttage für Anfangs- und Enddatum long wochen, werktage_rest, diff; puts("Geben Sie das erste Datum ein"); // Wandelt das erste Datum in Gesamttage um strcpy(puffer, datum_eingeben()); gesamt_anf = datum_umwandeln(puffer); puts("Geben Sie das zweite Datum ein"); // Wandelt das zweite Datum in Gesamttage um strcpy(puffer, datum_eingeben()); gesamt_end = datum_umwandeln(puffer); /* Vielleicht muss man zuerst die Werktage berechnen und diese dann abziehen Das lässt sich allerdings sehr einfach bewerkstelligen. */ diff = gesamt_end - gesamt_anf; // Berechnet die Differenz wochen = (diff / 7); // Berechnet Wochenanzahl werktage_rest = (diff % 7); // Berechnet Resttage (ang. Tage beginnen mit Montag) diff = (wochen*5) + werktage_rest; // Berechnet die Werktage printf("\nUnterschied in Werktagen: %ld", diff); getch(); return 0; } char *datum_eingeben(void) { int zahlen_ok = NEIN; int zeichen_ok = NEIN; static char puffer[10+1]; int mlen; int tag; int monat; int jahr; char *zgr; while ( zahlen_ok == NEIN ) { while ( zeichen_ok == NEIN ) // ERZWINGT EINGABE-FORMAT: XX.XX.XXXX (X = Ziffer) { fgets(puffer, 11, stdin); fflush(stdin); if ( (isdigit(puffer[0])) && (isdigit(puffer[1])) && (puffer[2] == '.') && (isdigit(puffer[3])) && (isdigit(puffer[4])) && (puffer[5] == '.') && (isdigit(puffer[6])) && (isdigit(puffer[7])) && (isdigit(puffer[8])) && (isdigit(puffer[9])) ) { zeichen_ok = JA; } } zgr = puffer; // UMWANDLUNG DES DATUMS VON STRING AUF VARIABLEN sscanf(zgr, "%2ld%", &tag); zgr += 3; sscanf(zgr, "%2ld%", &monat); zgr += 3; sscanf(zgr, "%4ld%", &jahr); zahlen_ok = JA; if ( (jahr < 0) || (jahr > 10000) ) // JAHR MUSS ZWISCHEN 0 UND 10000 LIEGEN { zahlen_ok = NEIN; zeichen_ok = NEIN; } if ( (monat < 1) || (monat > 12) ) // MONAT ZWISCHEN 1 UND 12 { zahlen_ok = NEIN; zeichen_ok = NEIN; } switch ( monat ) { case 1: mlen = 3; break; case 2: // WENN SCHALTJAHR, DANN 29.02. ERLAUBT { if ( (jahr % 4) == 0 ) mlen = 1; else mlen = 0; break; } case 3: mlen = 3; break; case 4: mlen = 2; break; case 5: mlen = 3; break; case 6: mlen = 2; break; case 7: mlen = 3; break; case 8: mlen = 3; break; case 9: mlen = 2; break; case 10: mlen = 3; break; case 11: mlen = 2; break; case 12: mlen = 3; break; }; if ( (tag < 1) || (tag > (28+mlen)) ) // TAGE MÜSSEN STIMMEN { zahlen_ok = NEIN; zeichen_ok = NEIN; } } return puffer; } unsigned long datum_umwandeln(char str_datum[]) { int tag; int monat; int schaltjahre; long jahr; char *zgr; // UMWANDLUNG DES DATUMS VON STRING AUF VARIABLEN zgr = str_datum; sscanf(zgr, "%2ld%", &tag); zgr += 3; sscanf(zgr, "%2ld%", &monat); zgr += 3; sscanf(zgr, "%4ld%", &jahr); // *** BEGINN DER UMRECHNUNG AUF GESAMTTAGE *** // WENN JAHR EIN SCHALTJAHR IST UND DER MONAT GRÖßER ALS FEBRUAR IST --> ADDIERE EINEN TAG if ( ((jahr % 4) == 0) && (monat > 2)) { tag++; } // ZÄHLT ALLE SCHALTJAHRE SEIT DEM JAHRE 0000 schaltjahre = (jahr/4); // WANDELT DIE JAHRE IN TAGE UM jahr *= 365; // WANDELT DIE MONATE IN TAGE UM monat--; switch ( monat ) { case 0: monat = 0; break; case 1: monat = 31; break; case 2: monat = 59; break; case 3: monat = 90; break; case 4: monat = 120; break; case 5: monat = 151; break; case 6: monat = 181; break; case 7: monat = 212; break; case 8: monat = 243; break; case 9: monat = 273; break; case 10: monat = 304; break; case 11: monat = 334; break; }; tag += monat + schaltjahre + jahr; return tag; }
-
Danke, das sieht doch schon sehr brauchbar aus und leuchtet ein. Dass es dafür aber keine Standartfunktion gibt?
Ich habe dein Programm noch nicht ausprobiert, aber es sieht gut aus und macht wohl fast genau das, was ich brauche.
Was mir nun noch fehlt sind die Feiertage. Ich denke mal, dass ich das selbst hinbekomme.Danke,
Spophie
-
Genau, es sieht hübsch aus und rechnet dazu auch noch falsch!
-
@Simonek:
Du weisst das ein Schaltjahr nicht nur alle 4 Jahre stattfindet, sondern auch alle 100 Jahre nicht stattfindet und alle 400 Jahre dann doch wieder?
-
Nein, das wusste ich noch nicht
So lernt man immer wieder dazu...das Programm müsste man demnach danach anpassen...
-
Hallo Simonek,
tröste Dich, sogar das so hoch renommierte M$-Excel rechnet falsch und behauptet, dass 1900 ein ´Schaltjahr gewesen sei *g*