Hi,
ich versuche mich gerade an einem kleinen Script, das mir iterativ für
jedes Jahr eine Seite als Kalender mit allen Feiertagen generiert. Die
festen Feiertage sind ja trivial, die kann man als Tabelle/Array ablegen
aber die beweglichen Feiertage muss man jedes Jahr neu berechnen, da sie
vom Osternsonntag abgeleitet werden. Und genau bei dieser
Differenzberechnung bin ich auf ein Phänomen getoßen, das ich nicht
verstehe.
Die Berechnung des eigentlichen Ostersonntags nehme ich mit der Funktion
*easter_days($current_year)* vor [1]. Anschließende manuelle Korrektur
(um hier schon Fehler durch die Verrechnung zu vermeiden) auf den
korrekten Tag und Monat. Abgleich mit diversen Tabellen, z.B. [2], [2a]
bestätigt die Korrektheit auch in Schaltjahren sowie jenseits des
Unix-Timestamp-Intervalls.
1 | <?php
|
2 | $current_year = 2021;
|
3 |
|
4 | // EASTER SUNDAY
|
5 | // https://www.php.net/manual/de/function.easter-days.php
|
6 | $easter_days = easter_days($current_year); // days since MARCH 21th
|
7 | $easter_sunday_month = (int)(($easter_days + 21) / 31) + 3;
|
8 | $easter_sunday_day = ($easter_days + 21) % 31;
|
9 | if($easter_sunday_day == 0)
|
10 | {
|
11 | // Apr. 0th ~~~> Mar. 31th
|
12 | $easter_sunday_day = 31;
|
13 | $easter_sunday_month = 3;
|
14 | }
|
15 | echo "\nOstersonntag:\t" . $current_year . "-" . $easter_sunday_month . "-" . $easter_sunday_day . "\n";
|
So weit, so happy.
Aus dem Datum des Ostersonntags versuche ich nun, die anderen Feiertage,
die die eine bestimmte Zeit davor oder danach liegen zu berechnen
mittels der Funktionen *date_sub()* bzw. *date_add()* [3], [4], die
eigentlich einen Alias sind für die objektorientierten Befehle
*DateTime::sub ()* bzw. *DateTime::add ()* [5], [6].
Da ich leider mit Objektorientierung keine Erfahrung habe, halte ich
mich weiter an den prozeduralen Ansatz. Ich habe verstanden, dass die
*date_sub()* ein DateTime-Objekt erwartet, das sie bearbeiten kann,
welches ich wie im Beispiel mit der *date_create()*-Funktion [7] aus
meinen Ostersonntags-Daten erstelle. Fein!
Erstelle ich jedes Mal dieses Objekt(?) neu, bevor ich mit der
date_sub() bzw. _add drauf zugreife, funktioniert es wie erwartet:
1 | <?php
|
2 | ...
|
3 | // ASCHERMITTWOCH: 46 days before Easter Sunday
|
4 | $date_temp_obj = date_create($current_year . '-' . $easter_sunday_month . '-' . $easter_sunday_day);
|
5 | date_sub($date_temp_obj, date_interval_create_from_date_string('46 days'));
|
6 | $temp_day = date_format($date_temp_obj, 'd');
|
7 | $temp_month = date_format($date_temp_obj, 'm');
|
8 | echo "\nAschermittwoch:\t" . $current_year . "-" . $temp_month . "-" . $temp_day;
|
9 |
|
10 | // KARFREITAG: 2 days before before Easter Sunday
|
11 | $date_temp_obj = date_create($current_year . '-' . $easter_sunday_month . '-' . $easter_sunday_day);
|
12 | date_sub($date_temp_obj, date_interval_create_from_date_string('2 days'));
|
13 | $temp_day = date_format($date_temp_obj, 'd');
|
14 | $temp_month = date_format($date_temp_obj, 'm');
|
15 | echo "\nKarfreitag:\t" . $current_year . "-" . $temp_month . "-" . $temp_day;
|
16 | ...
|
Hier kann man sich von der Funktion des vollständigen Quellcodes in
einer Sandbox überzeugen:
https://sandbox.onlinephpfunctions.com/code/12373b779ddc9e565e42149aeb83909a7efab4bb
Resultat:
1 | THIS WORKS CORRECTLY :-)
|
2 |
|
3 | Ostersonntag: 2021-4-4
|
4 |
|
5 | Aschermittwoch: 2021-02-17
|
6 | Karfreitag: 2021-04-02
|
7 | Himmelfahrt: 2021-05-13
|
8 | Pfingsten: 2021-05-23
|
Erstelle ich dieses Objekt jedoch nur ein Mal und speichere ich es in
einer Variable /$date_easter/ zwischen, um es wiederzuverwenden, erhalte
ich anfangs das korrekte Ergebis, anschließend aber falsche:
1 | <?php
|
2 | ...
|
3 | $date_easter = date_create($current_year . '-' . $easter_sunday_month . '-' . $easter_sunday_day);
|
4 |
|
5 | // ASCHERMITTWOCH: 46 days before Easter Sunday
|
6 | $date_temp_obj = $date_easter;
|
7 | date_sub($date_temp_obj, date_interval_create_from_date_string('46 days'));
|
8 | $temp_day = date_format($date_temp_obj, 'd');
|
9 | $temp_month = date_format($date_temp_obj, 'm');
|
10 | echo "\nAschermittwoch:\t" . $current_year . "-" . $temp_month . "-" . $temp_day;
|
11 | // calculation OK
|
12 |
|
13 | // KARFREITAG: 2 days before before Easter Sunday
|
14 | $date_temp_obj = $date_easter;
|
15 | date_sub($date_temp_obj, date_interval_create_from_date_string('2 days'));
|
16 | $temp_day = date_format($date_temp_obj, 'd');
|
17 | $temp_month = date_format($date_temp_obj, 'm');
|
18 | echo "\nKarfreitag:\t" . $current_year . "-" . $temp_month . "-" . $temp_day;
|
19 | // calculation WRONG! Aschermittwoch - 2 days
|
20 | ...
|
Hier das vollständige Programm in der Sandbox:
https://sandbox.onlinephpfunctions.com/code/0f965cf07997bfd4c19d5961c0e1ec30df7c2f6d
Resultat:
1 | THIS DONT WORK :-(
|
2 |
|
3 | Ostersonntag: 2021-4-4
|
4 |
|
5 | Aschermittwoch: 2021-02-17
|
6 | Karfreitag: 2021-02-15
|
7 | Himmelfahrt: 2021-03-26
|
8 | Pfingsten: 2021-05-14
|
Wie Sie sehen, wird der Aschermittwoch beide Male korrekt berechnet, der
Karfreitag wird dann aber auf den Aschermittwoch referenziert (2 Tage
davor) statt auf den Ostersonntag aus /$date_easter/. Und so setzt sich
das fort: Himmelfahrt wird auf diesen falschen Karfreitag referenziert
(+39 Tage). Bei Pfingsten bin ich dann von allen guten Geistern
verlassen: +40 Tage auf Ostersonntag bzw. +49 Tage auf die falsche
Himmelfahrt.
Ich habe das Gefühl, dass der Befehl
1 | $date_temp_obj = $date_easter;
|
gar nicht funktioniert, sonder mit dem alten date_temp_obj
weiterarbeitet.
Aber ich verstehe nicht, warum? Wie kann ich das beheben?
Der Workaround mit jedes mal neu /date_create(.)/ aufrufen funktioniert
zwar, ist aber unschön. Ich hoffe, Sie verstehen mein Anliegen.
Könnte mir bitte jemand erklären, was der Fehler ist.
Vielen Dank im Voraus!
Beste Grüße, Marek
[1] https://www.php.net/manual/de/function.easter-days.php
[2] http://www.othmar.at/aktuell/ostern/osterdatum.html
[2a] http://www.maa.clell.de/StarDate/feiertage.html
[3] https://www.php.net/manual/de/function.date-sub.php
[4] https://www.php.net/manual/de/function.date-add.php
[5] https://www.php.net/manual/de/datetime.sub.php
[6] https://www.php.net/manual/de/datetime.add.php
[7] https://www.php.net/manual/de/function.date-create.php
P.S. Auf meinem Server läuft PHP-Version 7.0.4. aber auch mit neueren
Versionen in der Sandbox lässt sich das Fehlverhalten reproduzieren.