Feiertage berechnen

Beim Einbinden von Ferengis Terminverwaltung für den Designer in meine V2-IPS ist mir aufgefallen, das es die ToniTools (bisher) nicht für V2 gibt. Also musste ich eine andere Lösung für das Thema Feiertage finden. Als Ergebnis habe ich die folgenden PHP-Funktionen geschrieben (bzw. zusammenkopiert :D), die ich hiermit allen interessierten zur Verfügung stellen möchte:

Das gesamte Konstrukt besteht aus 2 Hilfs-, einer Berechnungs- und 2 Auswertefunktionen:

Zunächst die Berechnungsfunktion:


// Errechnet das Datum des Ostersonntags für ein gegebenes Jahr
function easter($year) {
    if($year > 2038 || $year < 1970) {
        return false;
    } else {
        $a = $year % 19;
        $b = $year % 4;
        $c = $year % 7;
        $m = ((8 * ($year / 100) + 13) / 25) - 2;
        $s = ($year / 100) - ($year / 400) - 2;
        $M = (15 + $s - $m) % 30;
        $N = (6 + $s) % 7;
        $d = ($M + 19 * $a) % 30;
        if ($d == 29) {
            $D = 28;
        } elseif ($d == 28 && $a >= 11) {
            $D = 27;
        } else {
            $D = $d;
        }
        $e = (2 * $b + 4 * $c + 6 * $D + $N) % 7;
        $delta = $D + $e + 1;
        $easter = gmmktime(0, 0, 0, 3, 21, $year) + $delta * (24 * 3600);
        return $easter;
    }
}

Diese Funktion (ist glaube ich die Berechnung des Ostersonntags nach Gauss) hab ich mir kopiert in in php umkodiert…

Dann noch die 2 Hilfsfunktionen, welche von den beiden Auswertefunktion benötigt werden:


// Beseitigt Stundenanteile in einem UNIX-Zeitstempel
function ResetHours(&$timestamp) {
    $hour = date('G', $timestamp);
    $timestamp -= ($hour * 3600);
}
function ResetHour($timestamp) {
    $hour = date('G', $timestamp);
    $timestamp -= ($hour * 3600);
    return $timestamp;
}

Die erste Funktion ist eine sog. „Callback“-Funktion (wird von array_walk in der Auswertefunktion Feiertage aufgerufen) um für alle Elemente eines Arrays die Stundenanteile der Zeitstempel zu entfernen.
Die zweite Funktion ist fast identisch, lediglich der erste Parameter wird dabei nicht als Referenz übergeben sondern das Ergebnis als Returnwert geliefert.

Jetzt noch die erste Auswertefunktion, „Feiertage“. Sie liefert ein Array mit allen Feiertagen des angegebenen Jahres zurück. Es ist ein assoziatives Array, die Feiertagsnamen stellen die Schlüssel dar, der Wert ist jeweils ein entsprechender UNIX-Zeitstempel:


// Berechnet alle festen und variablen Feiertage eines gegebenen Jahrs.
// Die Feiertage werden als Array zurückgeliefert, wobei der Key dem
// Feiertagsnamen entspricht und der Wert dem entsprechenden Zeitstempel.
function Feiertage($year) {
    $OneDay = 24 * 60 * 60;
    $easter = easter($year);
    if(!$easter) {
        return false;
    } else {
        $advday = date('w', gmmktime(0, 0, 0, 11, 26, $year));
        $advent = gmmktime(0, 0, 0, 11, 26, $year) + (($advday == 0 ? 0 : 7 - $advday) * $OneDay);
        $holidays['Neujahr']                   = gmmktime(0, 0, 0,  1,  1, $year);
        $holidays['Heilige Drei Könige']       = gmmktime(0, 0, 0,  1,  6, $year);
        $holidays['Rosenmontag']               = $easter - (48 * $OneDay);
        $holidays['Fastnacht']                 = $easter - (47 * $OneDay);
        $holidays['Aschermittwoch']            = $easter - (46 * $OneDay);
        $holidays['Karfreitag']                = $easter - (2 * $OneDay);
        $holidays['Ostersonntag']              = $easter;
        $holidays['Ostermontag']               = $easter + (1 * $OneDay);
        $holidays['Tag der Arbeit']            = gmmktime(0, 0, 0,  5,  1, $year);
        $holidays['Christi Himmelfahrt']       = $easter + (39 * $OneDay);
        $holidays['Pfingstsonntag']            = $easter + (49 * $OneDay);
        $holidays['Pfingstmontag']             = $easter + (50 * $OneDay);
        $holidays['Fronleichnam']              = $easter + (60 * $OneDay);
        $holidays['Mariä Himmelfahrt']         = gmmktime(0, 0, 0,  8, 15, $year);
        $holidays['Tag der deutschen Einheit'] = gmmktime(0, 0, 0, 10,  3, $year);
        $holidays['Reformationstag']           = gmmktime(0, 0, 0, 10, 31, $year);
        $holidays['Allerheiligen']             = gmmktime(0, 0, 0, 11,  1, $year);
        $holidays['Buß- und Bettag']           = $advent - (11 * $OneDay);
        $holidays['1. Advent']                 = $advent;
        $holidays['2. Advent']                 = $advent + (7 * $OneDay);
        $holidays['3. Advent']                 = $advent + (14 * $OneDay);
        $holidays['4. Advent']                 = $advent + (21 * $OneDay);
        $holidays['Heiligabend']               = gmmktime(0, 0, 0, 12, 24, $year);
        $holidays['1. Weihnachtsfeiertag']     = gmmktime(0, 0, 0, 12, 25, $year);
        $holidays['2. weihnachtsfeiertag']     = gmmktime(0, 0, 0, 12, 26, $year);
        $holidays['Silvester']                 = gmmktime(0, 0, 0, 12, 31, $year);
        array_walk($holidays, 'ResetHours');
        return $holidays;
    }
}

Die letzte Funktion habe ich aus Platzgründen im nächsten Beitrag untergebracht.

Hier also die letzte Funktion „Feiertag“:


// Berechnet das Datum eines bestimmten Feiertags im gegebenen Jahr.
// Liefert als Ergebnis den Zeitstempel des Feiertags bzw. false wenn das Jahr
// ungültig oder der Feiertag unbekannt ist.
function Feiertag($year, $name) {
    $OneDay = 24 * 60 * 60;
    $easter = easter($year);
    if(!$easter) {
        return false;
    } else {
        $advday = date('w', gmmktime(0, 0, 0, 11, 26, $year));
        $advent = gmmktime(0, 0, 0, 11, 26, $year) + (($advday == 0 ? 0 : 7 - $advday) * $OneDay);
        
        switch (strtolower($name)) {
            case 'neujahr':                   return ResetHour(gmmktime(0, 0, 0,  1,  1, $year));
            case 'heilige drei könige':       return ResetHour(gmmktime(0, 0, 0,  1,  6, $year));
            case 'rosenmontag':               return ResetHour($easter - (48 * $OneDay));
            case 'fastnacht':                 return ResetHour($easter - (47 * $OneDay));
            case 'aschermittwoch':            return ResetHour($easter - (46 * $OneDay));
            case 'karfreitag':                return ResetHour($easter - (2 * $OneDay));
            case 'ostersonntag':              return ResetHour($easter);
            case 'ostermontag':               return ResetHour($easter + (1 * $OneDay));
            case 'tag der arbeit':            return ResetHour(gmmktime(0, 0, 0,  5,  1, $year));
            case 'christi himmelfahrt':       return ResetHour($easter + (39 * $OneDay));
            case 'pfingstsonntag':            return ResetHour($easter + (49 * $OneDay));
            case 'pfingstmontag':             return ResetHour($easter + (50 * $OneDay));
            case 'fronleichnam':              return ResetHour($easter + (60 * $OneDay));
            case 'mariä himmelfahrt':         return ResetHour(gmmktime(0, 0, 0,  8, 15, $year));
            case 'tag der deutschen einheit': return ResetHour(gmmktime(0, 0, 0, 10,  3, $year));
            case 'reformationstag':           return ResetHour(gmmktime(0, 0, 0, 10, 31, $year));
            case 'allerheiligen':             return ResetHour(gmmktime(0, 0, 0, 11,  1, $year));
            case 'buß- und bettag':           return ResetHour($advent - (11 * $OneDay));
            case '1. advent':                 return ResetHour($advent);
            case '2. advent':                 return ResetHour($advent + (7 * $OneDay));
            case '3. advent':                 return ResetHour($advent + (14 * $OneDay));
            case '4. advent':                 return ResetHour($advent + (21 * $OneDay));
            case 'heiligabend':               return ResetHour(gmmktime(0, 0, 0, 12, 24, $year));
            case '1. weihnachtsfeiertag':     return ResetHour(gmmktime(0, 0, 0, 12, 25, $year));
            case '2. weihnachtsfeiertag':     return ResetHour(gmmktime(0, 0, 0, 12, 26, $year));
            case 'silvester':                 return ResetHour(gmmktime(0, 0, 0, 12, 31, $year));
            default:                          return false;
        }
    }
}

Zum gebrauch einfach alle Funktionen in einem Skript zusammen kopieren.

Die Funktion Feiertag kann man z.B. folgendermaßen einsetzen:

Codebeispiel:



if (time() < Feiertag(date('Y'), 'Aschermittwoch')) {
    echo 'Freut euch, die fünfte Jahreszeit ist noch nicht vorbei!';
}

Hallo Thorsten,

da hast Du ein paar schöne Funktionen zusammen gestellt. Nur bei Deinem Beispiel muss es time() und nicht time<> heißen. Oder als Abfrage, wie lange es bis zu einem Termin noch dauert:

$OneDay = 24 * 60 * 60;

if (time() < Feiertag(date('Y'), 'heiligabend'))
    echo "noch ".round((Feiertag(date('Y'),'heiligabend')-time())/$OneDay+0.5)." Tage bis Weihnachten";

Ich wünsche einen schönen Tag.

Christoph.

Hallo Thorsten,

schal mal hier.:wink:

@Christop:

Beispiel muss es time() und nicht time<> heißen
Ups! War wohl schon ein wenig spät heute morgen! :eek:

Du hast natürlich vollkommen recht, sind ja die Klammern des Funktionsaufrufs - der Vergleichsoperator steht ja dahinter (<).

Habe das Beispiel mal schnell korrigiert…

@Ferengi-Master:

Wenns das dann für alle gibt ist das natürlich echt spitze. Aber als ich die Funktionen geschrieben habe waren die ToniTools für V2 noch ein frommer Wunsch. :cool:
Auf der anderen Seite finde ich es manchmal etwas „Overkill“ eine umfangreiche Fkt.Biblio wie die TT’s einzubinden wenn ich nur mal schnell eine Funktion brauche, die ich mir auch leicht selbst schreiben könnte.
Und ganz nebenbei ist es auch noch praktisches Material für php-Anfänger, denn der Code ist ja nicht sooo komplex und sollte relativ leicht zu verstehen sein.

Btw: Toni, ich finde es echt super was du so alles an AddOn’s für IPS auf die Beine stellst :smiley: - dafür kann man dir gar nicht oft genug Anerkennung zollen.
Ich durfte selber mal eine Statistik-SW in VB5 für meinen Arbeitgeber schreiben - ist eine gewaltige Aufgabe, besonders die anschließende Entwanzung, die Pflege
und, leider oft vernachlässigt, die Dokumentation der SW. :rolleyes:

Wenns das dann für alle gibt ist das natürlich echt spitze. Aber als ich die Funktionen geschrieben habe waren die ToniTools für V2 noch ein frommer Wunsch.
Auf der anderen Seite finde ich es manchmal etwas „Overkill“ eine umfangreiche Fkt.Biblio wie die TT’s einzubinden wenn ich nur mal schnell eine Funktion brauche, die ich mir auch leicht selbst schreiben könnte.
Und ganz nebenbei ist es auch noch praktisches Material für php-Anfänger, denn der Code ist ja nicht sooo komplex und sollte relativ leicht zu verstehen sein.

Da hast Du natürlich recht, mit eigenen Funktionen ist man auch flexibel. Wollte nur auf das gute Stück von Toni hinweisen.:wink:
Und ich freue mich, das auch Du die Terminverwaltung einsetzt. Sitze heute schon einige Stunden an Codeoptimierung, habe aus den 3 Scripten jetzt eins gemacht. Gibt dann bald ein Update. Muß noch ein bisl testen.:wink:

Hallo Thorsten,

vielen Dank für das Script … ich stehe aber gerade ein wenig auf dem Schlauch … wie frage ich ab, ob heute ein Feiertag ist und wie müßte ich eine Abfrage gestalten, die mir nur ausgibt ob ein bestimmter Feiertag ist?
Dann müßte ich quasi ein neues Array mit den Tagen erstellen die ich auswerten will und schauen ob heute mit einem der Tage aus dem Array überein stimmen?

Gruß
Jens

Hallo Jens,

wenn Du eine umfangreiche Feiertagsberechnung suchts kannst Du auch mal in den source code von Torros WIIPS schauen unter \wiips_2.1.zip\web\modules\calendar findes Du eine Klasse Calendarium in der sich einige schöne Funktionen dazu befinden.:wink:

@Tetrapack

Ich habe mir dazu ein einfaches Script gestrickt, was mir eine Boolean-Variable auf True setzt, wenn ein Feiertag ist. Dabei habe ich auch noch die Schulferien mit einbezogen und noch ein paar zusätzliche Dinge (wie man sieht), die man rauseditieren kann…

<?
/*
***********************************************************
Berechnet den Wochentag, freie Tage, Schulferien, Feiertage
und setzt die Variablen
***********************************************************
File     : Wochentag_u_freie_Tage.ips.php
Trigger  : Zyklisch
Interval : 1 Stunde
*/


//Aktuelles Datum (Format "JJJJMMTT")

   $today = date ("md");                                                        // aktueller Tag
   $todayy = date ("Ymd");                                                      // aktuelles Datum
   $year = date ("Y");                                                          // aktuelles Jahr
   $wochentag = GetValueString(24833 /*[_Steuerung\aktueller Wochentag [Nr]]*/ );      // aktuelle Wochentagnummer
   
// Ferien- u.Urlaubstermine (Format "JJJJMMTT")

   $herbstferienbeginn = "20091012";                                            // Herbstferienbeginn
   $herbstferienende = "20091024";                                              // Herbstferienende
   
   $weihnachtsferienbeginn = "20081220";                                        // Weihnachtsferienbeginn
   $weihnachtsferienende = "20090103";                                          // Weihnachtsferienende
   
   $winterferienbeginn = "20090202";                                            // Winterferienbeginn
   $winterferienende = "20090207";                                              // Winterferienende
   
   $osterferienbeginn = "20090406";                                             // Osterferienbeginn
   $osterferienende = "20090417";                                               // Osterferienende
   
   $pfingstferienbeginn = "20080513";                                           // Pfingstferienbeginn
   $pfingstferienende = "20080516";                                             // Pfingstferienende
   
   $sommerferienbeginn = "20090625";                                            // Sommerferienbeginn
   $sommerferienende = "20090805";                                              // Sommerferienende
   
   $schulfrei1 = "20080502";                                                    // schulfreier Tag #1
   $schulfrei2 = "20080502";                                                    // schulfreier Tag #2
   $schulfrei3 = "20080502";                                                    // schulfreier Tag #3
   
   $urlaubbeginn1 = "20080000";                                                 // Urlaubsbeginn Urlaub #1
   $urlaubende1 = "20080000";                                                   // Urlaubsende Urlaub #1
   
   $urlaubbeginn2 = "20080000";                                                 // Urlaubsbeginn Urlaub #2
   $urlaubende2 = "20080000";                                                   // Urlaubsende Urlaub #2
   

// *** Wochentag setzen (Sonntag = 7, Montag = 1) ***
$wday = date("w");
$wday1 = array("7","1","2","3","4","5","6");
$wday2 = array("Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag");
//echo "Heute ist Wochentag ", $wday1[$wday], " ($wday2[$wday])","
";
SetValueString(24833 /*[_Steuerung\aktueller Wochentag [Nr]]*/  , $wday1[$wday]);
SetValueString(53384 /*[_Steuerung\aktueller Wochentag [Name]]*/ , $wday2[$wday]);

// *** Tag des Jahres setzen ***
SetValueString(46827 /*[_Steuerung\aktueller Tag des Jahres]*/ , date("z"));

// *** Kalenderwoche setzen ***
SetValueString(14535 /*[_Steuerung\Kalenderwoche]*/ , date("W"));


// *** bewegliche Feiertage ***
if ( ($today == strftime("%m%d",(easter_date() - 2 * 86400)))                   // Karfreitag
//or ($today == "0512")                                                           // Test-Tag (aktuellen Tag eintragen zum Funktionstest)
or ($today == strftime("%m%d",(easter_date() )))                                // Ostersonntag
or ($today == strftime("%m%d",(easter_date() + 1 * 86400)))                     // Ostermontag
or ($today == strftime("%m%d",(easter_date() + 39 * 86400)))                    // Christi Himmelfahrt
or ($today == strftime("%m%d",(easter_date() + 49 * 86400)))                    // Pfingstsonntag
or ($today == strftime("%m%d",(easter_date() + 50 * 86400)))                    // Pfingstmontag
//or ($today == strftime("%m%d",(easter_date() + 60 * 86400)))                    // Fronleichnam
//or (($wochentag == 3) and ($today >= "1116") and ($today <= "1122"))            // Buß u. Bettag

// *** feste Feiertage ***
or ($today == "0101")                                                           // Neujahr
or ($today == "0106")                                                           // Heilige Drei Könige
or ($today == "0501")                                                           // 1. Mai
or ($today == "1003")                                                           // Tag der dt. Einheit
or ($today == "1031")                                                           // Reformationstag
//or ($today == "1101")                                                           // Allerheiligen
or ($today == "1225")                                                           // 1. Weihnachtsfeiertag
or ($today == "1226")                                                           // 2. Weihnachtsfeiertag


// *** freie Tage ***
or ($today == "1224")                                                           // Heiliger Abend
or ($today == "1231")                                                           // Silvester


// *** Schulferien und schulfreie Tage***
or (($todayy >= $herbstferienbeginn) and ($todayy <= $herbstferienende))        // Herbstferien
or (($todayy >= $weihnachtsferienbeginn) and ($todayy <= $weihnachtsferienende))// Weihnachtsferien
or (($todayy >= $winterferienbeginn) and ($todayy <= $winterferienende))        // Winterferien
or (($todayy >= $osterferienbeginn) and ($todayy <= $osterferienende))          // Frühjahrsferien
or (($todayy >= $pfingstferienbeginn) and ($todayy <= $pfingstferienende))      // Pfingstferien
or (($todayy >= $sommerferienbeginn) and ($todayy <= $sommerferienende))        // Sommerferien
or ($todayy == $schulfrei1)                                                     // schulfreier Tag #1
or ($todayy == $schulfrei2)                                                     // schulfreier Tag #2
or ($todayy == $schulfrei3)                                                     // schulfreier Tag #3


// *** Urlaub ***
or (($todayy >= $urlaubbeginn1) and ($todayy <= $urlaubende1))                  // 1. Urlaubszeitraum
//or (($todayy >= $urlaubbeginn2) and ($todayy <= $urlaubende2))                  // 2. Urlaubszeitraum
)


// *** "Freier Tag"-Variable setzen ***
   {
   SetValueBoolean(39649 /*[_Steuerung\Freier Tag]*/ , true);                          // Es ist ein freier Tag

//   echo "Heute sind Schulferien, ein schulfreier Tag oder Urlaub, ein freier Tag oder ein Feiertag. ","
";
   }
   else
   {
   SetValueBoolean(39649 /*[_Steuerung\Freier Tag]*/ , false);                         // Es ist kein freier Tag

//   echo "Heute sind keine Schulferien, kein schulfreier Tag, kein Urlaub, kein freier Tag und kein Feiertag. ","
";
   }


// 1. Advent berechnen - Weihnachtsbeleuchtung 2 Tag(e) vorher einschalten
$adventbel = date("md",mktime(0,0,0,11,(26+(7-date("w",mktime(0,0,0,11,26,$year))))))-2;
$advent = date("d.m.Y",mktime(0,0,0,11,(26+(7-date("w",mktime(0,0,0,11,26,$year))))));
if ($adventbel == "1200") $adventbel = "1130";
if ($adventbel == "1199") $adventbel = "1129";
if ($adventbel == "1198") $adventbel = "1128";
if ($adventbel == "1197") $adventbel = "1127";
if ($adventbel == "1196") $adventbel = "1126";
if ($adventbel == "1195") $adventbel = "1125";
//echo "1. Advent ist am ", $advent, "
";

if ( ( ("$today") >= ("$adventbel")                                             // ab dann einschalten
or ("$today") <= ("0105") ) )                                                   // bis 5.Januar einschalten
   {
   SetValueBoolean(37389 /*[_Allgemein\Weihnachtsbeleuchtung [aktiv]]*/ , true);
//      echo "Es ist Adventszeit und die Weihnachtsbeleuchtung wird eingeschaltet.","
";
   }
   else
   {
   SetValueBoolean(37389 /*[_Allgemein\Weihnachtsbeleuchtung [aktiv]]*/ , false);
//      echo "Es ist keine Adventszeit und die Weihnachtsbeleuchtung wird nicht eingeschaltet.","
";
   }

?>

P.S. Mittlerweile auf IPS V2 angepasst, aber für V1 auch kein Problem. Einfach die ID´s ersetzen.

Danke für den Vorschlag, auch eine feine Möglichkeit :wink:

Werde mir dann alles mal ansehen und das verwenden was mir am besten paßt.

Gruß
Jens