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