]> git.karo-electronics.de Git - oswald.git/blobdiff - ui/calendar.c
Oh boy... lots of changes, too many to describe
[oswald.git] / ui / calendar.c
diff --git a/ui/calendar.c b/ui/calendar.c
new file mode 100644 (file)
index 0000000..6271e12
--- /dev/null
@@ -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
+}
+
+