#include "oswald.h" #include "calendar.h" unsigned char is_leap(const unsigned int year) { /* the rule is, everything that can be devided by 4 is leap. * Exception: the year can be devided by 100, then it is not, * except it canbe devided by 400, then it is again. */ if ((year % 400) == 0) return 1; else if ((year % 100) == 0) return 0; else if ((year % 4) == 0) return 1; return 0; } unsigned short days_of_month(const unsigned int uMonat, const unsigned int uJahr) { // invalid,January,Febuary,March,April,May,June,July,August,September,October,November,December int arrTageImMonat[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (uMonat == 2) { // Febuary: distinguish leap if (is_leap(uJahr)) return 29; else return 28; } if ((uMonat >= 1) && (uMonat <= 12)) return arrTageImMonat[uMonat]; else { return 0; } } short getAnzahlTageImJahr(const unsigned int uJahr) { return (is_leap(uJahr)) ? 366 : 365; } short getWochentag(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr) { // ungült Jan Feb Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez unsigned char arrMonatsOffset[13] = { 0, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; short nErgebnis = 0; // Monat / Tag - Plausi prüfen: if ((uTag > 31) || (uMonat > 12) || (uMonat <= 0) || (uTag <= 0) || (uJahr <= 0)) { return -1; } unsigned char cbTagesziffer = (uTag % 7); unsigned char cbMonatsziffer = arrMonatsOffset[uMonat]; unsigned char cbJahresziffer = ((uJahr % 100) + ((uJahr % 100) / 4)) % 7; unsigned char cbJahrhundertziffer = (3 - ((uJahr / 100) % 4)) * 2; // Schaltjahreskorrektur: if ((uMonat <= 2) && (is_leap(uJahr))) cbTagesziffer = cbTagesziffer + 6; nErgebnis = (cbTagesziffer + cbMonatsziffer + cbJahresziffer + cbJahrhundertziffer) % 7; // Ergebnis: // 0 = Sonntag // 1 = Montag // 2 = Dienstag // 3 = Mittwoch // 4 = Donnerstag // 5 = Freitag // 6 = Samstag return nErgebnis; } short getTagDesJahres(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr) { // Der wievielte Tag des Jahres ist dieser Tag if ((uMonat == 0) || (uMonat > 12)) { return -1; } unsigned int uLokalTag = uTag; unsigned int uLokalMonat = uMonat; while (uLokalMonat > 1) { uLokalMonat--; uLokalTag += days_of_month(uLokalMonat, uJahr); } return uLokalTag; } short getKalenderwoche(short uTag, short uMonat, short uJahr) { // Berechnung erfolgt analog DIN 1355, welche besagt: // Der erste Donnerstag im neuen Jahr liegt immer in der KW 1. // "Woche" ist dabei definiert als [Mo, ..., So]. short nTagDesJahres = getTagDesJahres(uTag, uMonat, uJahr); // Berechnen des Wochentags des 1. Januar: short nWochentag1Jan = getWochentag(1, 1, uJahr); // Sonderfälle Freitag und Samstag if (nWochentag1Jan >= 5) nWochentag1Jan = nWochentag1Jan - 7; // Sonderfälle "Jahresanfang mit KW - Nummer aus dem Vorjahr" if ( (nTagDesJahres + nWochentag1Jan) <= 1) { return getKalenderwoche(31, 12, uJahr - 1); } short nKalenderWoche = ((nTagDesJahres + nWochentag1Jan + 5) / 7); // 53 Kalenderwochen hat grundsätzlich nur ein Jahr, // welches mit einem Donnerstag anfängt ! // In Schaltjahren ist es auch mit einem Mittwoch möglich, z.B. 1992 // Andernfalls ist diese KW schon die KW1 des Folgejahres. if (nKalenderWoche == 53) { boolean bIstSchaltjahr = is_leap(uJahr); if ((nWochentag1Jan == 4) // Donnerstag || (nWochentag1Jan == -3) // auch Donnerstag || ((nWochentag1Jan == 3) && bIstSchaltjahr) || ((nWochentag1Jan == -4) && bIstSchaltjahr)) { ; // Das ist korrekt und erlaubt } else nKalenderWoche = 1; // Korrektur des Wertes } return nKalenderWoche; } void getOsterdatum(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat) { // Berechnet für ein beliebiges Jahr das Osterdatum. // Quelle des Gauss - Algorithmus: Stefan Gerth, // "Die Gauß'sche Osterregel", Nürnberg, Februar 2003. // http://krapfen.org/content/paper/Schule/Facharbeit/Berechnung_des_Osterfestes.pdf unsigned int a = uJahr % 19; unsigned int b = uJahr % 4; unsigned int c = uJahr % 7; int k = uJahr / 100; int q = k / 4; int p = ((8 * k) + 13) / 25; unsigned int Egz = (38 - (k - q) + p) % 30; // Die Jahrhundertepakte unsigned int M = (53 - Egz) % 30; unsigned int N = (4 + k - q) % 7; unsigned int d = ((19 * a) + M) % 30; unsigned int e = ((2 * b) + (4 * c) + (6 * d) + N) % 7; // Ausrechnen des Ostertermins: if ((22 + d + e) <= 31) { *uTag = 22 + d + e; *uMonat = 3; } else { *uTag = d + e - 9; *uMonat = 4; // Zwei Ausnahmen berücksichtigen: if (*uTag == 26) *uTag = 19; else if ((*uTag == 25) && (d == 28) && (a > 10)) *uTag = 18; } // Offsets für andere Feiertage: // Schwerdonnerstag / Weiberfastnacht -52 // Rosenmontag -48 // Fastnachtsdienstag -47 // Aschermittwoch -46 // Gründonnerstag -3 // Karfreitag -2 // Ostersonntag 0 // Ostermontag +1 // Christi Himmelfahrt +39 // Pfingstsonntag +49 // Pfingstmontag +50 // Fronleichnam +60 // Mariä Himmelfahrt ist stets am 15. August (Danke an Michael Plugge!) } void getViertenAdvent(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat) { // Berechnet für ein beliebiges Jahr das Datum des 4. Advents-Sonntags. // Der 4. Adventssonntag ist stets der Sonntag vor dem 1. Weihnachtsfeiertag, // muß also stets in der Periode [18. - 24.12.] liegen: *uMonat = 12; // Das steht jedes Jahr fest :-) short nWoTag = getWochentag(24, 12, uJahr); // Wochentag des 24.12. ermitteln *uTag = 24 - nWoTag; // Offsets: Der Buß- und Bettag liegt stets 32 Tage vor dem 4. Advent }