Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /***************************************************************************************
- * This program (ANSI C) computes the dates of the most important
- * Catholic church holidays, additionally gives Orthodox Easter and
- * Christmas dates, computes the Protestant "Buss- und Bettag" and
- * outputs the results as a list of CSV. This program contains no
- * safety measures and implements only a rudimentary error handling.
- *
- * Compile: gcc -ansi -pedantic -O3 -o kft kft.c
- * Invoke: kft [year] [year] (kft=Kirchliche FeierTage)
- * Bug: See commentary on "int jahr_aus_systemdatum (void)"
- * Last change: September 16th, 2023.
- * Copyright (C) <December 3rd, 2015> Henning POLZER,
- * send comments and error reports to: h underscore polzer at gmx dot de.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- ***************************************************************************************/
- /* Erforderlich fuer: */
- #include <math.h> /* floor() */
- #include <stdio.h> /* printf() */
- #include <stdlib.h> /* atoi() */
- #include <time.h> /* time() */
- #define GRENZE 5000 /* Obere Jahresgrenze fuer Berechnungen */
- typedef unsigned int ganz; /* 0..maxint; der Kuerze halber "ganz" */
- typedef struct {
- ganz t,m,j; /* Tag, Monat, Jahr */
- } datum; /* Wichtigster Variablentyp des gesamten Programms */
- /*
- Die Variable "ks" steht fuer "KalenderStil" und erhaelt die Werte
- 1 fuer den julianischen und
- 2 fuer den gregorianischen
- Kalender. Die Vereinbarung erfolgt aber nicht hier, sondern jeweils
- lokal in den Funktionen.
- */
- /***********************************************************************
- * Prueft, ob das uebergebene Jahr ein Schalt- oder Gemeinjahr im
- * julianischen bzw. gregorianischen Kalender ist. Die Funktion
- * liefert als Fehlerwert -1 zurueck, falls das nicht existente
- * Jahr 0 uebergeben wurde und ist deshalb vorzeichenbehaftet.
- * (Dieses Programm (kft.c) wertet den moeglichen Fehlerwert
- * allerdings nicht aus, weil schon das Hauptprogramm prueft, ob
- * sich die Jahresgrenzen im erlaubten Bereich >0 bewegen. Der
- * Fehlerwert bleibt hier nur zur Erhaltung der universellen
- * Verwendbarkeit der Funktion erhalten.)
- ************************************************************************/
- int schaltjahr(int stil,int jahr)
- {
- ganz j=jahr,schalt=0,ks=stil;
- if(j==0) return -1; /* Fehler: Kein Jahr 0 */
- if(ks==1) /* julian. Kal. */
- if(j% 4==0) schalt=1;
- if(ks==2) { /* gregorian. Kal. */
- if(j% 4==0) schalt=1;
- if(j%100==0) schalt=0;
- if(j%400==0) schalt=1;
- } /* if(ks==2) */
- return schalt;
- } /* schaltjahr() */
- /*************************************************************
- * Verwandelt gegebenes Tagesdatum in eine laufende Nummer.
- * Mit den Funktionen ganz datum_in_nummer(ganz,datum) und
- * datum nummer_in_datum(ganz,ganz,ganz) kommen die
- * Berechnungen ohne die julianische Tagesnummer aus, das
- * ist (hoffentlich) einfacher verstaendlich.
- * (Ursprungsfassung vom 17.06.2015.)
- **************************************************************/
- ganz datum_in_nummer(ganz stil,datum tagesdatum)
- {
- datum dat=tagesdatum;
- /* Schalttag zur evtl.en Addition bereithalten: */
- ganz ks=stil,schalttag=schaltjahr(ks,dat.j),summe=0;
- switch(dat.m) {
- /* Schalttag zunaechst noch unwichtig: */
- case 1: summe= dat.t; break;
- case 2: summe= 31+dat.t; break;
- /* Tagesnr. ab Maerz vom Schalttag beeinflusst: */
- case 3: summe= 59+dat.t+schalttag; break;
- case 4: summe= 90+dat.t+schalttag; break;
- case 5: summe=120+dat.t+schalttag; break;
- case 6: summe=151+dat.t+schalttag; break;
- case 7: summe=181+dat.t+schalttag; break;
- case 8: summe=212+dat.t+schalttag; break;
- case 9: summe=243+dat.t+schalttag; break;
- case 10: summe=273+dat.t+schalttag; break;
- case 11: summe=304+dat.t+schalttag; break;
- case 12: summe=334+dat.t+schalttag; break;
- } /* switch(dat.m) */
- return summe;
- } /* datum_in_nummer() */
- /***********************************************************
- * Verwandelt laufende Nummer eines Tages in ein Datum:
- * (Ursprungsfassung vom 17.06.2015.)
- ************************************************************/
- datum nummer_in_datum(ganz stil,ganz tagesnummer,ganz jahreszahl)
- {
- ganz ks=stil,nr=tagesnummer,tag=0,monat=0,
- jahr=jahreszahl,schalttag=schaltjahr(ks,jahr);
- datum tempdatum;
- /* Jahr kann schon hier zugewiesen werden: */
- tempdatum.j=jahr;
- if(schalttag==0) {
- if((nr>= 1)&&(nr<= 31)) { tag=nr; monat= 1; }
- if((nr>= 32)&&(nr<= 59)) { tag=nr- 31; monat= 2; }
- if((nr>= 60)&&(nr<= 90)) { tag=nr- 59; monat= 3; }
- if((nr>= 91)&&(nr<=120)) { tag=nr- 90; monat= 4; }
- if((nr>=121)&&(nr<=151)) { tag=nr-120; monat= 5; }
- if((nr>=152)&&(nr<=181)) { tag=nr-151; monat= 6; }
- if((nr>=182)&&(nr<=212)) { tag=nr-181; monat= 7; }
- if((nr>=213)&&(nr<=243)) { tag=nr-212; monat= 8; }
- if((nr>=244)&&(nr<=273)) { tag=nr-243; monat= 9; }
- if((nr>=274)&&(nr<=304)) { tag=nr-273; monat=10; }
- if((nr>=305)&&(nr<=334)) { tag=nr-304; monat=11; }
- if((nr>=335)&&(nr<=365)) { tag=nr-334; monat=12; }
- } /* if(schalttag==0) */ else
- if(schalttag==1) {
- if((nr>= 1)&&(nr<= 31)) { tag=nr; monat= 1; }
- if((nr>= 32)&&(nr<= 60)) { tag=nr- 31; monat= 2; }
- if((nr>= 61)&&(nr<= 91)) { tag=nr- 60; monat= 3; }
- if((nr>= 92)&&(nr<=121)) { tag=nr- 91; monat= 4; }
- if((nr>=122)&&(nr<=152)) { tag=nr-121; monat= 5; }
- if((nr>=153)&&(nr<=182)) { tag=nr-152; monat= 6; }
- if((nr>=183)&&(nr<=213)) { tag=nr-182; monat= 7; }
- if((nr>=214)&&(nr<=244)) { tag=nr-213; monat= 8; }
- if((nr>=245)&&(nr<=274)) { tag=nr-244; monat= 9; }
- if((nr>=275)&&(nr<=305)) { tag=nr-274; monat=10; }
- if((nr>=306)&&(nr<=335)) { tag=nr-305; monat=11; }
- if((nr>=336)&&(nr<=366)) { tag=nr-335; monat=12; }
- } /* if(schalttag==1) */
- tempdatum.t=tag;
- tempdatum.m=monat;
- return tempdatum;
- } /* nummer_in_datum() */
- /*******************************************************************************
- * Verwandelt ein Datum im julian. Kalender in ein Datum im greg. Kalender.
- * Nach: J. Bach, Die Zeit- und Festrechnung der Juden unter besonderer
- * Beruecksichtigung der gaussschen Osterformel nebst einem immerwährenden
- * Kalender, Freiburg i. B. 1908, 26.
- * Vgl. auch Chr. Zeller, Kalender-Formeln, Acta Mathematica 9 (1887), 135.
- ********************************************************************************/
- datum konv_in_greg(datum julian_datum)
- {
- datum dat=julian_datum;
- ganz h=floor(dat.j/100),
- /* 1, weil Datum des julian. Kal. uebergeben */
- nr=datum_in_nummer(1,dat),
- neue_nr=nr+(h-floor(h/4)-2);
- /* S.o., Kommentar zur Variablen "nr": */
- return nummer_in_datum(1,neue_nr,dat.j);
- } /* konv_in_greg() */
- /****************************************************************************
- * WochenTagsNummeR bestimmen nach:
- * Chr. Zeller, Kalender-Formeln, Acta Mathematica, Band 9 (1887), 131f.
- * So.=1, Mo.=2, Di.=3, Mi.=4, Do.=5, Fr.=6, Sa.=0
- *****************************************************************************/
- ganz wtnr(ganz stil,datum tagesdatum)
- {
- datum dat=tagesdatum;
- /* h NICHT "ganz"! h kann negativ werden, s.u. */
- int h,j=floor(dat.j/100),k=dat.j-j*100,ks=stil,m=dat.m,q=dat.t;
- if(m==1) { /* Januar 13. Monat des VORjahres */
- m=13;
- k--;
- } /* if(m==1) */
- if(m==2) { /* Februar 14. Monat des VORjahres */
- m=14;
- k--;
- } /* if(m==2) */
- if(ks==1) h=(q+floor(26*(m+1)/10)+k+floor(k/4)+5-j); else
- if(ks==2) h=(q+floor(26*(m+1)/10)+k+floor(k/4)+floor(j/4)-2*j);
- /* if(h<0)… ist unnoetig */
- while(h<0) /* S.o., Kommentar zur Vereinbarung von h */
- h+=7;
- return h%7;
- } /* wtnr() */
- /***************************************************
- * Wochentag nach Nummer bestimmen und ausgeben
- * Nummern nach: ganz wtnr(ganz,datum)
- ****************************************************/
- void wochentag_ausgeben(ganz nummer)
- {
- ganz n=nummer;
- switch(n) {
- case 0: printf ("Sa"); break;
- case 1: printf ("So"); break;
- case 2: printf ("Mo"); break;
- case 3: printf ("Di"); break;
- case 4: printf ("Mi"); break;
- case 5: printf ("Do"); break;
- case 6: printf ("Fr"); break;
- } /* switch(n) */
- printf(".");
- } /* wochentag_ausgeben() */
- /******************************************************************
- * Ostersonntag bestimmen nach: Chr. Zeller, Kalender-Formeln,
- * Acta Mathematica, Band 9 (1887), 133-136.
- *******************************************************************/
- datum ostersonntag(ganz stil,ganz jahr)
- {
- ganz a,b,d,n=jahr,monat=4,tag,ks=stil;
- datum ostern;
- if(ks==1) { /* julian. Kalender */
- a=n%19;
- b=(ganz)(19*n-floor(n/19)+15)%30;
- d=(ganz)(b+n+floor(n/4))%7;
- } /* if(ks==1) */
- if(ks==2) { /* gregorian. Kalender */
- a=n%19;
- b=(ganz)(19*n-floor(n/19)+15+(floor(n/100)-floor(n/300)-floor(n/400)))%30;
- d=(ganz)(b+n+floor(n/4)-(floor(n/100)-floor(n/400)-2))%7;
- } /* if(ks==2) */
- if((d==0)&&(b==29)) d=7; else
- if((d==0)&&(b==28)&&(a>10)) d=7;
- tag=21+b+7-d;
- if(tag>31) tag-=31; else monat=3;
- ostern.t=tag;
- ostern.m=monat;
- ostern.j=n;
- return ostern;
- } /* ostersonntag() */
- /******************************************
- * Datum des 1. Advents bestimmen
- * Nummern nach: ganz wtnr(ganz,datum)
- *******************************************/
- datum erster_advent(ganz stil,ganz jahr)
- {
- ganz basis,j=jahr,ks=stil,tag;
- datum dat;
- /*
- kfta() legt den Stil nach der Jahreszahl beim
- Funktionsaufruf automatisch fest, 1582 gilt z.T.
- noch der julianische Kalender, der Advent 1582
- liegt aber schon nach der Reform, deshalb
- wird hier gesondert festgelegt, dass Ende
- 1582 der gregorianische Kalender anzuwenden ist:
- */
- if(j==1582) ks=2;
- /* 27. Nov.: 331. Tag im Jahr+ggf. Schalttag: */
- basis=331+schaltjahr(ks,j);
- dat=nummer_in_datum(ks,basis,j);
- switch(wtnr(ks,dat)) {
- case 0: tag=basis+1; break;
- case 1: tag=basis ; break;
- case 2: tag=basis+6; break;
- case 3: tag=basis+5; break;
- case 4: tag=basis+4; break;
- case 5: tag=basis+3; break;
- case 6: tag=basis+2; break;
- } /* switch(wtnr(ks,dat)) */
- return (nummer_in_datum(ks,tag,j));
- } /* erster_advent() */
- /**************************************************************************
- * Datum des Weihnachtsfestes im julian. Kalender in entsprechendes
- * Datum des gregorian. Kalender verwandeln, analog zu "konv_in_greg";
- * eine separate Funktion ist noetig, weil der Kalenderstil fuer die
- * Schaltjahresberechnung hier jahresunabhaengig julianisch sein muss.
- * Wieder nach: Bach, Festrechnung, 26,
- * s.o.: datum konv_in_greg (datum julian_datum).
- ***************************************************************************/
- datum konv_orth_weihnachten(datum julian_datum)
- {
- datum dat=julian_datum;
- ganz h=floor(dat.j/100),
- /* 1, weil Datum des jul. Kal. uebergeben, auch unten: */
- nr=datum_in_nummer(1,dat),neue_nr=nr+(h-floor(h/4)-2);
- if(neue_nr>365+schaltjahr(1,dat.j)) { /* immer jul. Kalender */
- neue_nr-=(365+schaltjahr(1,dat.j));
- dat.j++; /* Jahresgrenze ueberschritten */
- } /* if(neue_nr>365+schaltjahr(1,dat.j) */
- return nummer_in_datum(1,neue_nr,dat.j);
- } /* konv_orth_weihnachten() */
- /*******************************************
- * kfta="Kirchliche FeierTage Ausgeben"
- * Die Ausgabe erfolgt als CSV, ein
- * Semikolon dient jeweils als Trenner.
- ********************************************/
- void kfta(ganz untergr,ganz obergr)
- {
- ganz jahr,ks,o=obergr,u=untergr;
- datum dat,neu;
- for(jahr=u;jahr<=o;jahr++) {
- if(jahr<1583) ks=1; else /* 1: julianischer Stil */
- ks=2; /* 2: gregorianischer Stil */
- /*
- Die obige automatische Festlegung des Stils wird z. T.
- ausser Kraft gesetzt, z.B. teilweise im Jahr 1582 oder
- wenn Formeln einen bestimmten Stil erfordern.
- */
- dat=ostersonntag(ks,jahr); /* Westkirche */
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)-46,jahr);
- printf("Aschermittw.: %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)- 2,jahr);
- printf("Karfreitag : %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- printf("Ostern: %2u.%2u.%4u; ",dat.t,dat.m,dat.j);
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)+39,jahr);
- printf("Chr. Himmelf.: %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)+49,jahr);
- printf("Pfingstso.: %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)+60,jahr);
- printf("Fronleichnam: %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)+68,jahr);
- printf("Herz-Jesu-Fr.: %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- printf("Mariae Himmelf.: "); /* Wochentag ausgeben */
- neu.t=15; /* Immer am 15. August */
- neu.m=8;
- neu.j=jahr;
- wochentag_ausgeben(wtnr(ks,neu));
- dat=erster_advent(ks,jahr); /* 1. Advent als Basis fuer… */
- neu=nummer_in_datum(ks,datum_in_nummer(ks,dat)-11,jahr); /* …Buss-/Bettag: */
- printf("; Buss/Bettag: %2u.%2u.%4u; ",neu.t,neu.m,neu.j);
- printf("1. Advent: %2u.%2u.%4u; ",dat.t,dat.m,dat.j); /* …1. Advent */
- if(jahr>=1582) { /* Orthodoxie behaelt julian. Kalender bei*/
- if(jahr>1582) { /* Ostern 1582 noch vor gregorian. Reform */
- printf("Orthodoxes Osterfest : ");
- dat=ostersonntag(1,jahr); /* 1 fuer Formel des jul. Kalenders */
- printf("%2u.%2u.%4u [JULIANISCH] ",dat.t,dat.m,dat.j);
- neu=konv_in_greg(dat);
- printf("= %2u.%2u.%4u im ",neu.t,neu.m,neu.j);
- printf("westlichen GREGORIANISCHEN Kalender; ");
- } /* if(jahr>1582) */
- /* Weihnachten 1582 schon nach Kalenderreform: */
- printf("Orthodoxes Weihnachten: 25.12.%4u [JULIANISCH] ",jahr);
- dat.t= 25;
- dat.m= 12;
- dat.j=jahr;
- neu=konv_orth_weihnachten(dat);
- printf("= %2u.%2u.%4u im ",neu.t,neu.m,neu.j);
- printf("westlichen GREGORIANISCHEN Kalender\n");
- } /* if(jahr>=1582) */
- } /* for(jahr=u;jahr<=o;jahr++) */
- } /* kfta() */
- /****************************************************************
- * Gewinnt aus den Sekunden seit 1.1.1970 das laufende Jahr.
- * ! BUG: Am 01. Januar bis 01:00 Uhr morgens wird !
- * ! anscheinend noch das Vorjahr zurueckgeliefert. !
- *****************************************************************/
- int jahr_aus_systemdatum(void)
- {
- long /* t speichert Sekunden seit 1.1.1970, 00:00h: */
- t=time(NULL),
- /* Anfangsjahr der UNIX-Zeit: */
- jahr=1970;
- do {
- /* Sekunden eines Jahres abziehen (60*60*24*365): */
- t-=31536000;
- /*
- Schaltjahr? Dann ggf. auch die Sekunden des
- Schalttages abziehen, 1970 und danach wird immer
- die Schaltregel des gregorianischen Kalenders
- beachtet, deshalb hat Stil hier immer den Wert 2:
- */
- if(schaltjahr(2,jahr)==1) t-=86400;
- jahr++; /* zum naechsten Jahr springen */
- } while(t>0);
- /* Kurz und weniger uebersichtlich: */
- /*
- while(t>0)
- schaltjahr(2,jahr++)?(t-=31622400):(t-=31536000);
- */
- return jahr-1;
- } /* jahr_aus_systemdatum() */
- /******************************************************************
- * Fehlermeldung bei falschem Programmaufruf. Die Ausgaben
- * sind zwar trivial, helfen aber, die optisch uebersichtliche
- * Struktur des Hauptprogramms zu erhalten.
- *******************************************************************/
- int fmeldung(ganz nummer)
- {
- ganz n=nummer;
- switch (n) {
- case 1: printf("Usage: kft [year] [year]\n"); break;
- case 2: printf("0<Year<=%u\n",GRENZE); break;
- } /* switch(n) */
- return 0;
- } /* fmeldung() */
- /**********************************************************************
- * Es muss dem Benutzer ueberlassen bleiben, theologisch sinnvolle
- * Jahreszahlen auszuwaehlen: Eine Berechnung des Osterdatums fuer
- * das Jahr 1 n.Chr. waere rechnerisch zwar moeglich, aber
- * theologisch nicht sinnvoll, ebensowenig ergaebe die Berechnung
- * des Fronleichnamsdatums fuer das Fruehmittelalter Sinn.
- ***********************************************************************/
- int main(int argc,char *argv[])
- {
- /*
- og: Obergrenze (Jahreszahl) fuer Feiertagsberechnung.
- ug: Untergrenze "-"
- t : Jahreszahlen tauschen, wenn Untergrenze>Obergrenze ist.
- */
- ganz og,ug,t;
- /* Jahr aus dem Systemdatum gewinnen: */
- ug=jahr_aus_systemdatum(); /* Bug beachten! */
- /*
- Falls mindestens ein Parameter angegeben wurde,
- diesen fuer ug verwenden:
- */
- if(argc>1) ug=atoi(argv[1]);
- if(ug>GRENZE) fmeldung(2); else
- if(argc>3) fmeldung(1); else
- if(argc==1) kfta(ug,ug); /* Systemdatum verwenden */ else
- if(ug==0) fmeldung(2); else
- if(argc==2) /* Feiertage eines Jahres berechnen */
- if(ug>GRENZE) fmeldung(2); else kfta(ug,ug); else
- if(argc==3) { /* … von Jahr1 bis Jahr2 ausgeben */
- og=atoi(argv[2]);
- if(og==0) fmeldung(2); else
- if(og!=0) {
- /* ug groesser als og? Werte tauschen: */
- ug>og?t=ug,ug=og,og=t:0;
- if(og>GRENZE) fmeldung(2); else kfta(ug,og);
- } /* if(og!=0) */ else fmeldung(1);
- } /* if(argc==3) */
- return 0;
- } /* main() */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement