Datums Berechnungen
Berechnung ob ein Jahr ein Schaltjahr ist
Ich beschränke mich hier auf die Berechnung der Schaltjahre nach
der gregorianischen Regel, die ab 1582 n.Chr. gilt. Sie besagt, dass
ein Jahr ein Schaltjahr ist, wenn es durch 4 ohne Rest, aber nicht
durch 100 ohne Rest Teilbar ist. Eine Ausnahme von letzterem gibt es,
wenn das Jahr durch 400 ohne Rest teilbar ist, ist es doch wieder ein
Schaltjahr.
Beispiel: Das Jahr 2100 ist durch 4 ohne Rest teilbar,wäre also
ein Schaltjahr. Da es jedoch auch durch 100 ohne Rest teilbar ist, ist
es doch kein Schaltjahr. Geteilt durch 400 bleibt ein Rest, es bleibt
also dabei, 2100 ist kein Schaltjahr.
Beispielcode
Tag des Jahres berechnen
Gehen wir zunächst davon aus, ein Jahr hätte 12 Monate mit je
31 Tagen. In diesem Fall müssten wir die Menge der abgelaufenen
Monate nehmen und den Tag im Monat addieren. Beispiel: 25.8.2000. Es
sind 7 Monate komplett (8-1) diese nehmen wir mal 31 und addieren dann
25. (8-1)*31+25 = 242. Nun stimmt dies nicht ganz, da ja nicht jeder
Monat 31 Tage hat. Für jeden der 7 vergangenen Monate die nur 30
Tage hatten müssen wir jeweils einen Tag abziehen. Dies wären
April und Juni. Wir müssen also 2 Tage abziehen. 242-2=240. Bleibt
noch der Februar, hier müssen wir wissen ob es sich um ein
Schaltjahr handelt, also ob der Februar 28 oder 29 Tage hat. Mit der 1.
Berechnungsmethode ermitteln wir, dass das Jahr 2000 ein Schaltjahr
ist, der Februar also 29 Tage hat. Da der Februar bereits vorbei ist
und so mit 31 Tagen berechnet wurde, müssen wir 31-29= 2 Tage
abziehen. 240-2= 238. Der 25.8.2000 ist also der 238. Tag des Jahres.
Wäre es kein Schaltjahr hätten wir (31-28= 3) einen weiteren
Tag, also 3 Tage abziehen müssen.
Beispielcode
Wochentag berechnen
Jetzt wirds kompliziert. Die hier vorgestellte Methode funktioniert nur
für Datumsangaben ab dem 1.1.2000. Zunächst brauchen wir ein
"Referenz Jahr", welches durch 400 ohne Rest teilbar ist. Hier bietet
sich das Jahr 2000 an. Der 1.1.2000 war (laut Blick auf den Kalender)
ein Samstag. Wir müssen uns also überlegen, wie viele
komplette Jahre seit dem 1.1.2000 vergangen sind. Haben wir den
2.2.2004, so rechnen wir 2004-2000 = 4. Es sind also 4 volle Jahre
vergangen(2000,2001,2002 und 2003). Gehen wir davon aus, dass jedes der
vergangenen Jahre 365 Tage hatte, so können wir 4*365= 1460 Tage rechnen. Hinzu
kommen die Tage des aktuellen Jahres, was beim 2.2.2004 nach der obigen
Berechnungsmethode 33 Tage sind. 1460+33= 1493 Tage. Nun müssen
wir eventuelle Schaltjahre mit einem extra Tag pro Schaltjahr
berücksichtigen. Um zu wissen wie viele Schaltjahre seit dem
1.1.2002 stattfanden berechnen wir 1493+((4-1) / 4-(4-1)/100+(4-1)/400=1493. Zu beachten ist,
dass bei den Divisionen der nachkomma Anteil nicht mit eingerechnet
werden darf, auch dürfen keine negativen Zahlen vorkommen. Das +(4-1)/4 ermittelt wie
häufig die Jahresdifferenz durch 4 teilbar ist, davon abgezogen -(4-1)/100 wird die Anzahl der
Jahrhunderte, in denen bekanntlich kein Schaltjahr stattfindet und dazu
wiederum die Jahre, die zwar Jahrhunderte sind, in denen dann aber,
weil sie durch 400 ohne Rest teilbar sind, doch wieder eins stattfindet
+(4-1)/400. Nun fehlt in der
Berechnung noch, dass das Jahr 2000 auch ein Schaltjahr ist. Wenn die
Jahresdifferenz größer Null ist, müssen wir noch einen
Tag addieren. 1493+1=1494. Die -1
in den Berechnungen muss sein, da sonst bei den Schaltjahren(z.B. 2004,
2008) ein Tag zu viel berechnet werden würde. Bis da hin haben wir
die Anzahl der Tage, die zwischen dem 1.1.2000 und dem 2.2.2004 liegen
(es sind 1494 Tage).
Nun berechnen wir daraus den Wochentag, dazu berechnen wir den Rest,
wenn wir 1494 durch 7 (weil die Woche 7 Tage hat) teilen. Der Rest
beträgt: 3. Da der Rest 1 wäre, denn wir den
1.1.2000 berechnet hätten und dies ein Samstag war, wir aber eine
Funktion haben möchten, die für Montag = 1,...Samstag = 6, Sonntag = 7 ausgeben soll,
rechnen wir 3+(6-1) = 8. Weil das Ergebnis
größer als 7 ist, rechnen wir 8-7= 1. Eins steht für
Montag. Der 2.2.2004 war also ein Montag.
Mit dieser Methode ließe sich auch die Zeit in Tagen zwischen
zwei Datumsangaben berechnen.
Die Berechnungsmethode lässt sich ein wenig optimieren, da 365 mod
7 = 1 ist. Bedeutet, jedes Jahr (welches kein Schaltjahr ist) beginnt
einen Wochentag später. Dadurch kann das 4*365 einfach durch 4 ersetzt
werden. Die Zahlen werden somit nicht so groß, was bei einer
Berechnung in einem Mikrocontroller Speicher und Rechenzeit
spart. Allerdings kann dann nicht mehr die Zeit zwischen zwei
Datumsangaben berechnet werden.
Beispiel für den heutigen Tag: 8.5.2004.
Ist Schaltjahr? (2004 mod 4) -> kein Rest
-> Schaltjahr
Tag des Jahres? 31*(5-1)+8-> 132. Der April mit 30
Tagen ist vorbei: 132-1-> 131. Da es ein Schaltjahr ist, hatte der
Februar 29 Tage, 131-2-> 129 Der 8.5.2004 ist der 129. Tag des Jahres.
Wochentag? jahrdiff =2004-2000->4.
4+(4-1)/4-(4-1)/100+(4-1)/400 -> 4
4+129->133
weil (4> 0): 133+1 -> 134
134 mod 7 -> 1
1+5 = 6. Heute ist Samstag.
Beispiel c Code:
/* Globale zur Verfügung stehenden Variablen:
//Variablen für die Zeit:
u08 dayofweek = 1, day = 1, month = 1;
u16 year = 2004;
u08 isschaltjahr;
*/
void calcschaltjahr(void) {
/* Die Berechnung erfolgt nach der gregorianischen Regel. */
if (((year % 4) == 0)&&((year % 100) != 0)) { //Wenn Jahr durch 4 ohne Rest teilbar, aber nicht durch 100
isschaltjahr = 1; //Dann Schaltjahr
}else {
isschaltjahr = 0; //Dann kein Schaltjahr
}
if ((year % 400) == 0) { //Wenn Jahr durch 400 teilbar
isschaltjahr = 1; //Dann doch wieder Schaltjahr
}
//
Die obige Funktion benötigt c.a. 158 Byte Flash in einem AVR
}
void calcweekday(void) {
//funktioniert vom Jahr 2000 bis zum Jahr 2255
u16 tagdesjahres;
u08 jahrdiff;
// auf u16 zu ändern um weiter als das Jahr 2255 rechnen zu können
u16 tempwochentag;
//Tag des Jahres berechnen
calcschaltjahr();//Dazu muss bekannt sein, ob es sich um ein Schaltjahr handelt
tagdesjahres = 31*(month-1);
if (month > 2) {
//Februar
tagdesjahres = tagdesjahres -3 +isschaltjahr;
}
if (month > 4) { tagdesjahres--; }
//April
if (month > 6) { tagdesjahres--; }
//Juni
if (month > 9) { tagdesjahres--; }
//September
if (month > 11) { tagdesjahres--; }
//November
tagdesjahres += day;
//Wochentag berechnen
jahrdiff = year -2000; //Das Referenzjahr muss durch 400 ohne Rest teilbar sein.
tempwochentag = jahrdiff + (jahrdiff-1) / 4 - (jahrdiff-1) / 100 + (jahrdiff-1) / 400 + tagdesjahres;
if (jahrdiff > 0) { //Weil das Referenzjahr auch ein Schaltjahr ist
tempwochentag++;
}
tempwochentag = (tempwochentag % 7)+5; //Normalerweise wäre Samstag=1 (Weil der 1.1.2000 ein Samstag ist), so ist Samstag=6
if (tempwochentag > 7) { //Überlauf
tempwochentag = tempwochentag -7;
}
dayofweek = tempwochentag;
//Die obige Funktion benötigt c.a. 182 Byte Flash in einem AVR
}
Verwendung auf eigenes Risiko.
Falls jemand Fehler findet, die die Berechnungsmethode oder den
Beispielcode betreffen, mir bitte Mailen.
m.marwedel <AT> onlinehome.de
Malte Marwedel
zuletzt geändert: 8.5.2004