Zellers Kongruenz in C#

Bei Zellers Kongruenz handelt es sich nicht wirklich um einen Algorithmus sondern viel mehr um eine Formel. Sie wurde 1882 von Christian Zeller veröffentlicht und dient dazu den Wochentag eines gegebenen Datums zu Berechnen. Dabei wird zwischen dem Gregorianischen Kalender, den wir heute benutzen und dem Julianischen Kalender unterschieden. Letzterer wurde von Julius Cäsar eingeführt und war mancherorts noch bis in das 20 Jahrhundert gültig.

Ein Datum für den gregorianischen Kalender lässt sich wie folgt berechnen:

ZellerGreg

Hierbei haben die einzelnen Variablen folgende Bedeutung:

  • h: Ist eine ganze Zahl die für den Wochentag steht
  • q: Ist der der Monatstag. Also zB. für den 15.03.1991 ist q=15
  • m: Ist der Monat. Also zB. für den 15.03.1991 ist m=3.
(Wichtig!: Januar und Februar werden nicht als erster und zweiter Monat gezählt. Sie werden zu dem vorherigen Jahr gezählt. Entsprechend ist im Januar m = 13 und Februar m = 14)
 
  • J: Steht für die für die ersten zwei Ziffern des Jahres. Also zB. für den 15.03.1991 ist J=19.
  • K: Steht für die für die letzten zwei Ziffern der Jahresangabe. Also zB. für den 15.03.1991 ist K=91.

Außerdem muss berücksichtigt werden, dass das Ergebnis h uns nicht wie erwartet, einen Wert zwischen 1 und 7 (Montag – Sonntag) liefert. Die Rückgabewerte sehen wie folgt aus.

zellertage

Bevor wir uns an ein Beispiel machen möchte ich noch kurz die eckigen Klammern in der Formel erklären. Diese nennen sich Gaußklammer. Sie treten in zwei Formen auf und können als Auf- bzw. Abrundungsklammer bezeichnet werden. Besser sind sie jedoch als Floor und Ceilingfunktion bekannt (also Boden- und Deckenfunktion). So ist beispielsweise:

floorceiling

So nun da wir alles nötige geklärt haben, nehmen wir einfach den 10.02.2014 als Beispiel. So ergibt sich:

q = 10

m = 14

(Siehe oben, der Februar wird als 14-er Monat des jeweiligen Vorjahres gezählt.)

J = 20

K = 13

(Siehe oben, da der Februar nicht zum Jahr 2014 zählt sondern zu 2013 ist hier K = 13.)

Mit diesen Werten können wir nun den entsprechenden Wochentag wie folgt berechnen:

ZellerExample

Wenn wir jetzt in der obigen Tabelle nachschauen können wir ablesen, dass der 10.02.2014 ein Montag gewesen sein muss.

Glücklicherweise bietet die Math-Bibliothek in .NET beides eine Floor- und eine Ceilingfunktion. So können wir die Berechnung der Zeller Kongruenz für den gregorianischen Kalender wie folgt implementierten.

//Erhält Tag, Monat und Jahr als Argument
        public static int ZellersCongruenceGregorian(double dd, double mm, double yyyy)
        {
            int h = 0;
            double q = dd;
            double m = mm;
            double y = yyyy;
            double J = 0;
            double K = 0;

            #region Hier werden Monat und Jahr angepasst für den Fall, dass es sich um den Januar oder Februar handelt
            switch ((int)m)
            {
                case 1:
                    m = 13;
                    y--;
                    break;
                case 2:
                    m = 14;
                    y--;
                    break;
            }
            #endregion

            #region Da wir das Jahr als Zahl vorliegen haben, müssen wir diese zunächst in J und K umwandeln
            //Wir machen das indem wir die Zahl zu einem String umwandeln.
            string yearString = y.ToString().Trim();
            //Und sie dann in jeweils zwei Teile zerlegen
            J = Int32.Parse(yearString.Substring(0, 2));
            K = Int32.Parse(yearString.Substring(2, 2));
            #endregion

            //Die Formel selbst kann in einer einzelnen Zeile implementiert werden.
            h = (int)((q + Math.Floor(((m + 1) * 26)/10) + K + Math.Floor(K/4) + Math.Floor(J/4) - 2 * J)%7);

            return h;
        }

Analog dazu lässt sich ein Datum im Julianischen Kalender mit folgender Formel berechnen:

zellerJul

Entsprechend müssen wir nur eine Kleinigkeit in der obigen Methode verändern um ZellerCongruenceJulian() zu implementieren.

//Erhält Tag, Monat und Jahr als Argument
        public static int ZellersCongruenceJulian(double dd, double mm, double yyyy)
        {
            int h = 0;
            double q = dd;
            double m = mm;
            double y = yyyy;
            double J = 0;
            double K = 0;

            #region Hier werden Monat und Jahr angepasst für den Fall, dass es sich um den Januar oder Februar handelt
            switch ((int)m)
            {
                case 1:
                    m = 13;
                    y--;
                    break;
                case 2:
                    m = 14;
                    y--;
                    break;
            }
            #endregion

            #region Da wir das Jahr als Zahl vorliegen haben, müssen wir diese zunächst in J und K umwandeln

            string yearString = y.ToString().Trim();
            J = Int32.Parse(yearString.Substring(0, 2));
            K = Int32.Parse(yearString.Substring(2, 2));
            #endregion

            //Wir müssen die Formel nur minimal ändern um einen Wochentag im Julianischen Kalender zu berechnen.
            h = (int)((q + Math.Floor(((m + 1) * 26) / 10) + K + Math.Floor(K / 4) + 5 - J) % 7);

            return h;
        }

Die beiden Methoden geben uns nur Zahlen aus die wir zwar anhand der obigen Tabelle ablesen können, es bietet sich jedoch an eine kleine Methode zu schreiben die die jeweilige Zahl als Wochentag ausspuckt. Hierzu implementieren wir ZellersCongruenceToString():

public static string ZellersCongruenceToString(int h)
        {
            //Hier entscheiden wir welchem Wochentag der gegebene Wert entspricht
            //und liefern den entsprechenden Wochentag als String aus.
            switch(h)
            {
                case 0:
                    return "Saturday";
                    break;
                case 1:
                    return "Sunday";
                    break;
                case 2:
                    return "Monday";
                    break;
                case 3:
                    return "Tuesday";
                    break;
                case 4:
                    return "Wednesday";
                    break;
                case 5:
                    return "Thursday";
                    break;
                case 6:
                    return "Friday";
                    break;
                default:
                    return "Could not convert given number to a String.";
                    break;
            }
        }
Advertisements
Dieser Beitrag wurde unter .NET, Algorithmen, Beispiel, Beispiel, c#, Mathematik, Modulo, Programmierung, Uncategorized abgelegt und mit , , , , , , , , , , , , , , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

w

Verbinde mit %s