Datums Berechnungen

Berechnung ob ein Jahr ein Schaltjahr ist

Dieser Text beschränkt sich 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

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 8.05.2004 (Datum dieses Textes):

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. Dieser Text wurde an einem Samstag verfasst.

Beispiel für den 23.03.2005.

Ist Schaltjahr? (2005 mod 4) -> Rest -> kein Schaltjahr
Tag des Jahres? 31*(3-1)+23-> 85. In diesem Jahr verging bisher kein Monat mit nur 30 Tagen, es ändert sich soweit erstmal nichts. Da es kein Schaltjahr ist, hatte der Februar 28 Tage, 85-3-> 82.  Der 23.03.2005 ist der 82. Tag des Jahres.
Wochentag? jahrdiff =2005-2000->5.
5+(5-1)/4-(5-1)/100+(5-1)/400 -> 6
6+82->88
weil (5> 0): 88+1 -> 89
89 mod 7 -> 5
5+5 = 10
weil (10 > 7): 10-7= 3. Dies ist ein Mittwoch.


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
}