--- /dev/null
+#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
+}
+
+