EisFuX: Pragmatischer Lösungsansatz

Beitrag lesen

(Hallo|Hi(ho)|Tag und Mahlzeit) Nick,

bevor ich jetzt jedem einzeln antworte, bedanke ich mich einfach an dieser Stelle ganz herzlich bei euch für eure fundierten Beiträge. (Ich hoffe, das ist im Sinne der Übersichtlichkeit. Andernfalls bin ich für Hinweise dankbar.)

Das ist ein hier ab und zu auftretendes Problem: Man diskutiert und dokumentiert gerne die Schwierigkeiten aller Randprobleme, anstatt zu versuchen, einen einigermaßen pragmatischen Lösungsansatz aufzuzeigen ... ;-)

Dafür bekomme ich bestimmt Haue. ;-)

Da mir die "Transformation von Polarkoordinaten, sphärische Trigonometrie und Reihenentwicklungen [...] [leider nicht] leicht von der Hand gehen", werde ich mich wohl auf den Ansatz mit dem tropischen Jahr konzentrieren.

Was ich im Laufe der Zeit gesammelt habe, sind ein paar Funktionen, die das Datum des jeweiligen astronomischen "Jahreszeitanfangs" berechnen (also eine für Frühling, eine für Sommer usw.). Auf welcher theoretischen Basis diese Funktionen funktionieren ist mir egal. Mir reicht in diesem Fall, dass sie funktionieren (deswegen heißen sie auch Funktionen ;-)).

Allerdings hab ich eben festgestellt, dass ich mir keinerlei Information notiert habe, an welchem Ort diese Jahreszeitanfänge gelten. Kalendervergleiche deuten auf irgendwo in Mitteleuropa (wahrscheinlich Berlin, also das was für "deutsche Kalender" amtlich ist) hin. Da muss ich wohl noch mal in meinen "Archiven" kramen.

Leider ist es mit diesen Funktionen allein nicht getan. Sie geben ein astronomisches Datum (astronomische Julianische Tagesnummer) zurück. Das wandle ich in eine "gewöhnliche" Tagesnummer (Tag des Jahres) um. Dasselbe müsstest du mit deinem Vergleichsdatum machen. Damit könntest du prüfen, welche der vier Jahreszeitenwechsel schon verstrichen sind.

Die folgende "Klasse" sollte alle benötigten Grundfunktionen enthalten. In eine Klasse gepackt wurde das Ganze ursprünglich wegen der gemeinsam genutzten Variable zur Zeitverschiebung (wegen der Sommerzeit). Das Ganze ist schon ein paar Jahre alt, ganz sicher kein Meisterwerk der Programmierkunst, aber zum Herumspielen mit Kalenderdaten und als Proof-of-Concept geeignet. Die benutzten Quellen finden sich in den Kommentaren.

  
class calendar {  
    function __construct() {  
        $this->_time_shift = 0; // (daylight savings time) in seconds  
    }  
  
    // first day of spring (astronomical)  
    function vernal_equinox($year = NULL) {  
        $jdn = $this->_sun_calc($year, 2451623.80984, 365242.37404, 0.05169, -0.00411, - 0.00057);  
        return $this->_ajdn_to_doy($jdn);  
    }  
  
    // midsummer (summer solstice)  
    function midsummer($year = NULL) {  
        $jdn = $this->_sun_calc($year, 2451716.56767, 365241.62603, 0.00325, 0.00888, -0.00030);  
        return $this->_ajdn_to_doy($jdn);  
    }  
  
    // first day of autumn (astronomical)  
    function autumnal_equinox($year = NULL) {  
        $jdn = $this->_sun_calc($year, 2451810.21715, 365242.01767, -0.11575, 0.00337, 0.00078);  
        return $this->_ajdn_to_doy($jdn);  
    }  
  
    // midwinter (winter solstice)  
    function midwinter($year = NULL) {  
        $jdn = $this->_sun_calc($year, 2451900.05952, 365242.74049, -0.06223, -0.00823, 0.0003);  
        return $this->_ajdn_to_doy($jdn);  
    }  
  
    // returns astronomical JDN for equinox and solstice  
    function _sun_calc($year, $a, $b, $c, $d, $e) {  
        $m = ($year - 2000) / 1000;  
        // formula and values for a, b, c, d, e taken from c-source "ve.c" found on  
        // http://hermetic.magnet.ch/cal_sw/ve/ve.htm  
        // ve.c itself uses a method given in Jean Meeus's "Astronomical Algorithms" (1991).  
        // es gibt eine Ausgabe von 2001:  
        // J. Meeus: Astronomical Algorithms. Willmann-Bell, Richmond 2000, 2nd ed., ISBN 0-943396-61-1, Kap. 27  
        // im wikipedia-artikel: http://de.wikipedia.org/wiki/Äquinoktium  
        // a + bm + cm^2 + dm^3 + em^4  
        $time = $a + $b * $m + $c * $m * $m * $d * $m * $m * $m + $e * $m * $m * $m * $m;  
        return $time;  
    }  
  
    // converts astronomical JDN to day_of_year (according to timeshift)  
    // returns array (year, day_of_year)  
    function _ajdn_to_doy($jdn) {  
        $date = $jdn + 0.5 + ($this->_time_shift / 86400);  
        // astronomical JDN to chronological plus local timeshift  
  
        $jdn = floor($date);  
  
        $ary = function_exists('cal_from_jd') ? cal_from_jd($jdn, CAL_GREGORIAN) : $this->_jd_to_greg($jdn);  
  
        list ($year, $doy) = $this->ymd_to_doy(array ($ary['year'], $ary['month'], $ary['day']));  
        return $doy;  
    }  
  
    // some hosters do not have calender extension enabled  
    // from http://php.net/manual/de/function.jdtogregorian.php#32561  
    // returns array (year, month, day_of_month)  
    function _jd_to_greg($julian = NULL) {  
        $julian = $julian - 1721119;  
        $calc1 = 4 * $julian - 1;  
        $year = floor($calc1 / 146097);  
        $julian = floor($calc1 - 146097 * $year);  
        $day = floor($julian / 4);  
        $calc2 = 4 * $day + 3;  
        $julian = floor($calc2 / 1461);  
        $day = $calc2 - 1461 * $julian;  
        $day = floor(($day + 4) / 4);  
        $calc3 = 5 * $day - 3;  
        $month = floor($calc3 / 153);  
        $day = $calc3 - 153 * $month;  
        $day = floor(($day + 5) / 5);  
        $year = 100 * $year + $julian;  
  
        if ($month < 10) {  
            $month = $month + 3;  
        }  
        else {  
            $month = $month - 9;  
            $year = $year + 1;  
        }  
        return array('year' => $year, 'month' => $month, 'day' => $day);  
    }  
  
    // converts date array (y, m, d) to year and day_of_year  
    // $ymd: array(year, month, day_of_month)  
    // returns array(year, day_of_year)  
    function ymd_to_doy($ymd = NULL ) {  
        if (!is_array($ymd) || NULL === $ymd[0] || NULL === $ymd[1] || NULL === $ymd[2]) {  
            return FALSE;  
        }  
        // does no normalization so far!  
        // according to J. Duglas Robertson: Tableless Date Conversion (Remark on Algorithm 398);  
        // Communications of the ACM; Vol. 15; Oct. 1972; 918;  
        // enhanced according to c't 1997-015-312  
        $d = intval(($ymd[1] + 10) / 13);  
        $e = $ymd[2] + intval((611 * ($ymd[1] + 2)) / 20) - 2 * $d - 91;  
        return array ($ymd[0], $e + ($this->leap_year($ymd[0]) ? $d : 0));  
    }  
  
}  

PS: Eine PHP-Funktion mit den hier verwendeten Formeln zu schreiben, dürfte ja nicht allzu schwer sein. Allerdings blicke ich da nicht so ganz durch und weiß daher auch nicht, wie genau das ist.

Nun, das ist die typische Einstellung von "Laien": Ich hab zwar keine Ahnung von der Thematik, aber es dürfte nicht schwer sein, das zu machen ... und bitte kostenlos. ;-)

Warum versuchst du nicht einfach die Formeln oder Algorithmen nach PHP umzusetzen? Die Berechnungen lassen sich mit ein paar Beispieldaten prüfen, der schon erwähnten Wikipedia-Tabelle oder einem Kalender entnehmen kannst.

Vielleicht mag da ja noch jemand einen Blick riskieren.

Ich werde einen Blick riskieren, weil mich alles, was mit Datum und Zeit und Berechnungen, die damit zusammenhängen interessiert. Möglicherweise hab ich dieses Formelpaket aber schon in meinem Archiv (dann hat es sicher nicht zur Lösung beigetragen).

MffG
EisFuX