]> git.karo-electronics.de Git - oswald.git/blob - ui/calendar.c
Oh boy... lots of changes, too many to describe
[oswald.git] / ui / calendar.c
1 #include "oswald.h"
2
3 #include "calendar.h"
4
5 unsigned char is_leap(const unsigned int year)
6 {
7   // Die Regel lautet: Alles, was durch 4 teilbar ist, ist ein Schaltjahr.
8   // Es sei denn, das Jahr ist durch 100 teilbar, dann ist es keins.
9   // Aber wenn es durch 400 teilbar ist, ist es doch wieder eins.
10
11         if ((year % 400) == 0)
12                 return 1;
13         else if ((year % 100) == 0)
14                 return 0;
15         else if ((year % 4) == 0)
16                 return 1;
17
18         return 0;
19 }
20
21 unsigned short days_of_month(const unsigned int uMonat, const unsigned int uJahr)
22 {
23         //                     ungült,Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez
24         int arrTageImMonat[13] = {  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
25
26         if (uMonat == 2) {
27                 // Februar: Schaltjahr unterscheiden
28                 if (is_leap(uJahr))
29                         return 29;
30                 else
31                         return 28;
32         }
33
34         if ((uMonat >= 1) && (uMonat <= 12))
35                 return arrTageImMonat[uMonat];
36         else {
37                 return 0;
38         }
39 }
40
41 short getAnzahlTageImJahr(const unsigned int uJahr)
42 {
43         return (is_leap(uJahr)) ? 366 : 365;
44 }
45
46 short getWochentag(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr)
47 {
48         //                       ungült Jan Feb Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez 
49         unsigned char arrMonatsOffset[13] = {  0,  0,  3,  3,  6,  1,  4,  6,  2,  5,  0,  3,  5};
50         short nErgebnis = 0;
51
52         // Monat / Tag - Plausi prüfen:
53         if ((uTag > 31) || (uMonat > 12) || (uMonat <= 0) 
54                 || (uTag <= 0) || (uJahr <= 0)) {
55                 return -1;
56         }
57
58         unsigned char cbTagesziffer = (uTag % 7);
59         unsigned char cbMonatsziffer = arrMonatsOffset[uMonat];
60         unsigned char cbJahresziffer = ((uJahr % 100) + ((uJahr % 100) / 4)) % 7;
61         unsigned char cbJahrhundertziffer = (3 - ((uJahr / 100) % 4)) * 2;
62
63         // Schaltjahreskorrektur:
64         if ((uMonat <= 2) && (is_leap(uJahr)))
65                 cbTagesziffer = cbTagesziffer + 6;
66   
67         nErgebnis = (cbTagesziffer + cbMonatsziffer + cbJahresziffer + cbJahrhundertziffer) % 7;
68
69         // Ergebnis:
70         // 0 = Sonntag
71         // 1 = Montag
72         // 2 = Dienstag
73         // 3 = Mittwoch
74         // 4 = Donnerstag
75         // 5 = Freitag
76         // 6 = Samstag
77         return nErgebnis;
78 }
79
80 short getTagDesJahres(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr)
81 {
82         // Der wievielte Tag des Jahres ist dieser Tag
83         if ((uMonat == 0) || (uMonat > 12)) {
84                 return -1;
85         }
86
87         unsigned int uLokalTag = uTag;
88         unsigned int uLokalMonat = uMonat;
89
90         while (uLokalMonat > 1) {
91                 uLokalMonat--;
92                 uLokalTag += days_of_month(uLokalMonat, uJahr);
93         }
94
95         return uLokalTag;
96 }
97
98 short getKalenderwoche(short uTag, short uMonat, short uJahr)
99 {
100         // Berechnung erfolgt analog DIN 1355, welche besagt:
101         // Der erste Donnerstag im neuen Jahr liegt immer in der KW 1.
102         // "Woche" ist dabei definiert als [Mo, ..., So].
103         short nTagDesJahres = getTagDesJahres(uTag, uMonat, uJahr);
104
105         // Berechnen des Wochentags des 1. Januar:
106         short nWochentag1Jan = getWochentag(1, 1, uJahr);
107
108         // Sonderfälle Freitag und Samstag
109         if (nWochentag1Jan >= 5) 
110                 nWochentag1Jan = nWochentag1Jan - 7;
111
112         // Sonderfälle "Jahresanfang mit KW - Nummer aus dem Vorjahr"
113         if ( (nTagDesJahres + nWochentag1Jan) <= 1) {
114                 return getKalenderwoche(31, 12, uJahr - 1);
115         }
116
117         short nKalenderWoche = ((nTagDesJahres + nWochentag1Jan + 5) / 7);
118
119         // 53 Kalenderwochen hat grundsätzlich nur ein Jahr, 
120         // welches mit einem Donnerstag anfängt !
121         // In Schaltjahren ist es auch mit einem Mittwoch möglich, z.B. 1992
122         // Andernfalls ist diese KW schon die KW1 des Folgejahres.
123         if (nKalenderWoche == 53) {
124                 boolean bIstSchaltjahr = is_leap(uJahr);
125
126                 if ((nWochentag1Jan  ==  4) // Donnerstag
127                         ||  (nWochentag1Jan  == -3) // auch Donnerstag
128                         ||  ((nWochentag1Jan ==  3) && bIstSchaltjahr)
129                         ||  ((nWochentag1Jan == -4) && bIstSchaltjahr)) {
130                         ; // Das ist korrekt und erlaubt
131                 } else
132                         nKalenderWoche = 1; // Korrektur des Wertes
133         }
134
135         return nKalenderWoche;
136 }
137
138 void getOsterdatum(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat)
139 {
140         // Berechnet für ein beliebiges Jahr das Osterdatum.
141
142         // Quelle des Gauss - Algorithmus: Stefan Gerth, 
143         // "Die Gauß'sche Osterregel", Nürnberg, Februar 2003. 
144         // http://krapfen.org/content/paper/Schule/Facharbeit/Berechnung_des_Osterfestes.pdf
145
146         unsigned int a = uJahr % 19;
147         unsigned int b = uJahr %  4;
148         unsigned int c = uJahr %  7;
149
150         int k = uJahr / 100;
151         int q = k / 4;
152         int p = ((8 * k) + 13) / 25;
153         unsigned int Egz = (38 - (k - q) + p) % 30; // Die Jahrhundertepakte
154         unsigned int M = (53 - Egz) % 30;
155         unsigned int N = (4 + k - q) % 7;
156
157         unsigned int d = ((19 * a) + M) % 30;
158         unsigned int e = ((2 * b) + (4 * c) + (6 * d) + N) % 7;
159
160         // Ausrechnen des Ostertermins:
161         if ((22 + d + e) <= 31) {
162                 *uTag = 22 + d + e;
163                 *uMonat = 3;
164         } else {
165                 *uTag = d + e - 9;
166                 *uMonat = 4;
167
168                 // Zwei Ausnahmen berücksichtigen:
169                 if (*uTag == 26)
170                         *uTag = 19;
171                 else if ((*uTag == 25) && (d == 28) && (a > 10))
172                         *uTag = 18;
173         }
174
175         // Offsets für andere Feiertage:
176
177         // Schwerdonnerstag / Weiberfastnacht -52
178         // Rosenmontag -48
179         // Fastnachtsdienstag -47
180         // Aschermittwoch -46
181         // Gründonnerstag -3
182         // Karfreitag -2
183         // Ostersonntag 0
184         // Ostermontag +1
185         // Christi Himmelfahrt +39
186         // Pfingstsonntag +49
187         // Pfingstmontag +50
188         // Fronleichnam +60
189
190         // Mariä Himmelfahrt ist stets am 15. August (Danke an Michael Plugge!)
191 }
192
193 void getViertenAdvent(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat)
194 {
195         // Berechnet für ein beliebiges Jahr das Datum des 4. Advents-Sonntags.
196         // Der 4. Adventssonntag ist stets der Sonntag vor dem 1. Weihnachtsfeiertag,
197         // muß also stets in der Periode [18. - 24.12.] liegen:
198   
199         *uMonat = 12; // Das steht jedes Jahr fest :-)
200   
201         short nWoTag = getWochentag(24, 12, uJahr); // Wochentag des 24.12. ermitteln
202   
203         *uTag = 24 - nWoTag;
204
205         // Offsets: Der Buß- und Bettag liegt stets 32 Tage vor dem  4. Advent
206 }
207
208