Problem 2000/Das Schaltjahr 2000 und der Streit um die "Kalenderformel"

Hat sich Gauß geirrt?

31.10.1997

Das Problem 2000 zieht, wie könnte es anders sein, einen Rattenschwanz weiterer Schwierigkeiten nach sich. Da gibt es beispielsweise das Problem der Schaltjahrberechnung. Wie jeder weiß, ist ein Jahr, das sich ohne Rest durch vier teilen läßt, ein Schaltjahr.

Nicht jeder weiß aber, daß Jahrhundertjahre, zum Beispiel 1900, keine Schaltjahre sind, obwohl sie durch vier teilbar sind. Und viele Programmierer wußten offensichtlich nicht, daß alle ohne Rest durch 400 teilbaren Jahre wiederum doch Schaltjahre sind. Das bedeutet, daß in dem einen oder anderen Programm der 29. Februar 2000 nicht existiert.

Die unwissenden Programmierer, die nur von der Grundformel Gebrauch machten (alle durch vier teilbaren Jahre sind Schaltjahre) sind ausnahmsweise fein raus, weil ihre Formel die Jahre 1901 bis 2099 abdeckt. Es gibt aber Programmierer, die es genauer machen wollten, aber schlecht informiert waren und das Jahr 2000 für ein Gemeinjahr hielten.

Gesegnet die Firma, bei der die Schaltjahrberechnung nur in einem einzigen Unterprogramm erfolgt. Tatsächlich findet man Schaltjahrberechnungen meist in vielen Unterprogrammen und nicht nur dort, sondern auch in den Programmen selbst. Das bedeutet, daß nicht nur alle Unterprogramme, sondern auch alle Programme auf solche Berechnungen (und andere Kalenderroutinen) zu überprüfen sind.

Die falsche Schaltjahrberechnung kann andere Fehler nach sich ziehen, zum Beispiel eine irrige Berechnung des Wochentags. Denn wenn ein Programm das Jahr 2000 für ein Gemeinjahr hält, wird es alle Wochentage ab dem 1. März 2000 falsch berechnen. Das heißt, dieser Tag gilt nicht als Mittwoch, sondern als Dienstag, was natürlich zu falschen Aktionen führt, wenn der Wochentag von Bedeutung ist.

Der berühmte deutsche Mathematiker Carl Friedrich Gauß (1777-1855), den viele von uns, wenn überhaupt, nur noch vom Zehnmarkschein her kennen, hat nicht nur vielen mathematischen Erkenntnissen seinen Namen gegeben, so der Gaußschen Normalverteilung oder der Gaußschen Glockenkurve, sondern auch der Kalenderrechnung seine Highlights aufgesetzt.

Berechnung des Ostertags radikal vereinfacht

Der "Fürst der Mathematiker", wie er von seinen Zeitgenossen betitelt wurde, ist unter anderem für seine Osterformel berühmt, mit der er die außerordentlich komplexe Berechnung des Osterdatums auf wenige Rechenschritte reduzierte. Interessant ist allein schon der Anlaß, diese Formel zu erfinden: Gauß' Mutter konnte nicht schreiben und nur ein wenig lesen. Das Geburtsdatum ihres Sohnes wußte sie nur, so wie es damals üblich war, als acht Tage vor Christi Himmelfahrt zu bezeichnen. Das Kirchenfest hängt seinerseits vom Osterdatum ab, nämlich 39 Tage nach dem Ostersonntag, der nicht auf ein bestimmtes Datum festgelegt ist.

Auch für die Berechnung des Wochentags zu einem beliebigen Datum hat Gauß eine einfache Formel gefunden (siehe Kasten: Die Kalenderformel). Zuerst wird eine Summe berechnet, in die signifikante Faktoren des Datums eingehen, und diese Summe wird anschließend durch sieben geteilt. Der Rest, genauer der Modulowert, stellt die Nummer des Wochentags dar (0 = Sonntag, 1 = Montag und so weiter).

In einem Jahr-2000-Fragen- und Antwortkatalog im Internet behauptet nun ein gewisser Bear Giles, die Gaußsche Wochentagsformel habe einen Defekt, der erst ab dem Jahr 2000 zum Tragen komme: "Der Wochentag wird nach einer Formel berechnet, die Gauß (oder Euler?) zugeschrieben wird. Die Schaltjahrberechnung ist richtig, aber die Wochentagsberechnung nicht. Demnach würde dem 29.2.2000 (Dienstag) am 1.3.2000 ein Dienstag oder Donnerstag folgen. Ein ähnliches Problem ergibt sich mit dem 28.2.2001 und dem 1.3.2001."

Wenn das stimmte, würde es unserem Mathematikerfürsten kaum Abbruch tun, im Gegenteil: Es wäre so schön gewesen, wenn auch ein Mathematiker vom Range eines Gauß geirrt und seinen Jahr-2000-Fehler gemacht hätte. Ich programmierte daher die Gaußsche Formel in "Rexx" und testete sie für Daten des 20. und des 21. Jahrhunderts aus. Und siehe da, die Wochentagsberechnung war ab dem Jahr 2000 in den Monaten März bis Dezember teilweise falsch (siehe Kasten: Der "Fehler").

Leider kann sich Gauß gegen falsche Verdächtigungen nicht mehr wehren. Ich sah es daher als ein Gebot der Fairness an, keine voreiligen Schlüsse zu ziehen und mein Programm noch einmal zu überdenken. Tatsächlich stellte sich heraus, daß nicht Gauß, sondern ich und mit mir Bear Giles und viele andere Programmierer einen Fehler gemacht haben. Das Ergebnis der Gaußschen Formel kann nämlich negativ sein, und in diesem Fall muß man noch sieben auf die Wochentagsnummer addieren, um das richtige Resultat zu erhalten (siehe Kasten: Die Modulofunktion).

Hut ab, Herr Gauß! Heutige Programmierer können ihre Formeln spielend testen, indem sie den Computer alle nur möglichen Varianten durchrechnen lassen. Dagegen konnten Sie sich nur auf die Analyse Ihres Kopfes verlassen und haben - anders als die heutigen Programmierergenerationen - kein Jahr-2000-Problem in die Welt gesetzt.

Die Kalender-Formel

Die Wochentagsnummer wird nach der Gaußschen Formel in den folgenden Schritten berechnet (t = Tag, m = Monat, j = vierstelliges Jahr, a = zweistelliges Jahr, c = Jahrhundert):

Zuerst muß man vom Monat 2 subtrahieren: m = m - 2. Wenn m dabei kleiner 1 wird, ist zum Monat 12 zu addieren und vom Jahr 1 zu subtrahieren: m = m - 2, j = j - 1. Schließlich berechnet man das Zwischenergebnis z nach der Formel:

z = int(2,6 . m - 0,2) + t + a + int(a / 4) + int(c / 4) - 2 . c

Die Nummer des Wochentags (0 = Sonntag, 1 = Montag etc.) ergibt sich als Modulowert von z und 7: z mod 7.

Die Funktion int berechnet die größte Zahl, die kleiner oder gleich dem Operanden ist. Die Modulofunktion mod berechnen wir als Rest der Division der beiden Operanden, zum Beispiel ergibt j mod 100 = 1997 mod 100 = 19. Wenn der Rest negativ wird, nehmen wir den Absolutwert.

Beispiel: Eine Person wurde am 13.2.1955 geboren. Um den Wochentag ihres Geburtstages zu ermitteln, subtrahiere man 2 vom Monat: m = 0. Da der Monat nun kleiner 1 ist, addiere man 12 auf den Monat und vermindere die Jahreszahl um 1: m = 0 + 12 = 12, j = 1954, a = 54. Die Formel ergibt:

z = int(2,6 . 12 - 0,2) + 13 + 54 + int(54 / 4) + int(19 / 4) - 2 . 19

z = 31 + 13 + 54 + 13 + 4 - 38 = 77.

Der Modulowert 77 mod 7 ergibt 0. Das heißt, diese Person wurde an einem Sonntag geboren.

Der "Fehler"

Laut Bear Giles wird der Wochentag des 1. März 2000 nach der Gaußformel falsch berechnet. Wir subtrahieren die Zahl 2 vom Monat: m = 1. Das zweistellige Jahr a hat den Wert 00. Die Formel ergibt:

z = int(2,6 . 1 - 0,2) + 1 + 00 + int(00 / 4) + int(20 / 4) - 2 . 20

z = 2 + 1 + 0 + 0 + 5 - 40 = -32.

Der Rest aus -32 / 7 ergibt -4 und der Absolutwert von -4 ist 4, das heißt, der 1. März 2000 würde nach unserer Rechnung auf einen Donnerstag fallen. Tatsächlich ist es aber ein Mittwoch.

Die Modulofunktion

Wir haben - so wie es der Gewährsmann von Bear Giles wahrscheinlich auch getan hat - die Modulofunktion als absoluten Divisionsrest implementiert. Hätten wir eine Programmiersprache verwendet, die über die Modulofunktion mod verfügt (zum Beispiel Cobol oder PL/1), wäre das Problem gar nicht aufgetreten, da die versierten Compiler-Bauer die Modulofunktion selbstverständlich richtig implementiert haben. Tatsächlich ist die Modulofunktion für a mod b folgendermaßen definiert:

a mod b = a - (b . int(a / b))

Wenn wir nach diesem Muster -32 mod 7 berechnen, erhalten wir:

-32 - (7 . int(-32 / 7) = -32 - (7 . int(-4,57-) = -32 - (7 . (-5)) = -32 - (-35) = 3

Die Zahl 3 bedeutet, daß der 1.3. 2000 auf einen Mittwoch fällt - also ist die Welt wieder in Ordnung.

Übrigens bietet die Programmiersprache C einen besonders schönen Fallstrick. Der Operator "%" wird als Modulo-Operator bezeichnet, liefert aber tatsächlich nur den Divisionsrest. Was Wunder, wenn ein Programmierer diesen sogenannten Modulo-Operator auf Treu und Glauben verwendet und dann feststellen muß, daß er auf die Nase gefallen ist.

*Gerhard Leibrock ist Informatiker in Stuttgart.