X-Git-Url: https://git.karo-electronics.de/?p=oswald.git;a=blobdiff_plain;f=ui%2Fcalendar.c;fp=ui%2Fcalendar.c;h=6271e12a43b7edb9ae51561d46cfd02942019e8e;hp=0000000000000000000000000000000000000000;hb=5d0ff002cee35d109f4a60eff415b2db556fb8f4;hpb=dff6532fd5dbbd4a6c2f0fff2c428201b225c529 diff --git a/ui/calendar.c b/ui/calendar.c new file mode 100644 index 0000000..6271e12 --- /dev/null +++ b/ui/calendar.c @@ -0,0 +1,208 @@ +#include "oswald.h" + +#include "calendar.h" + +unsigned char is_leap(const unsigned int year) +{ + // Die Regel lautet: Alles, was durch 4 teilbar ist, ist ein Schaltjahr. + // Es sei denn, das Jahr ist durch 100 teilbar, dann ist es keins. + // Aber wenn es durch 400 teilbar ist, ist es doch wieder eins. + + 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) +{ + // ungült,Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez + int arrTageImMonat[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if (uMonat == 2) { + // Februar: Schaltjahr unterscheiden + 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 +} + +