209 lines
5.6 KiB
C
209 lines
5.6 KiB
C
#include "oswald.h"
|
|
|
|
#include "calendar.h"
|
|
|
|
unsigned char is_leap(const unsigned int year)
|
|
{
|
|
/* the rule is, everything that can be devided by 4 is leap.
|
|
* Exception: the year can be devided by 100, then it is not,
|
|
* except it canbe devided by 400, then it is again.
|
|
*/
|
|
|
|
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)
|
|
{
|
|
// invalid,January,Febuary,March,April,May,June,July,August,September,October,November,December
|
|
int arrTageImMonat[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
|
|
if (uMonat == 2) {
|
|
// Febuary: distinguish leap
|
|
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
|
|
}
|
|
|
|
|