Yeti: /(PHP) Netto-Arbeitstage effizient berechnen

Hallo Forum!

Ich habe mir eine PHP-Version der Excel-Funktion NETWORKDAYS bzw. NETTOARBEITSTAGE geschrieben, um berechnen zu können, wieviel Arbeitstage (abzüglich Wochenende und Feiertagen) zwischen zwei Daten liegen.
Dies habe ich ganz pragmatisch so gelöst, dass ich tageweise vom einen zum anderen Datum wander und den Zähler entweder hochsetze oder nicht. Am Ende der Schleife enthält der Zähler dann das richtige Ergebnis. Das Wochenende filtere ich über date("m")-Vergleiche heraus, die Feiertage kommen aus einem $_SESSION-Array.

Das funktioniert auch wunderbar, ist allerdings bei mehreren tausend Datensätzen und vier Arbeitstage-Differenzen pro Datensatz ziemlich langsam (1.557 Datensätze brauchten 26 Sekunden).

Gibt es einen effizienteren Weg oder sogar Algorithmus?

Danke im Voraus!
Gruß vom Yeti

--
Habe nun, ach! WInfo, BWL, und Mathe, Und leider auch Info!
Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!
Und bin so klug als wie zuvor!
sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:[ zu:) fl:| ss:) ls:< js:|
  1. das ist in der tat (voll) daneben.
    offensichtlich gehts dir nur um die wochenenden.
    mit den in jeder sprache verfügbaren datumsfunktionen läßt sich dies sinnvoller lösen.
    die funktion datediff oä. gibt die anzahl der tage zwischen 2 datumsangaben.
    für den wochentag (Mo-So) für den start- und endetag gibts auch funktionen.
    und mit mod (7tage/woche) gibts die anzahl der wochenenden.
    ich hoffe diese hinweise reichen.

    1. Hi,

      das ist in der tat (voll) daneben.

      Gut. Dann geht es wohl auch anders.

      offensichtlich gehts dir nur um die wochenenden.

      Nein, auch um Feiertage (für beinahe jeden User verschieden, weil über sechs Bundesländer verteilt).

      mit den in jeder sprache verfügbaren datumsfunktionen läßt sich dies sinnvoller lösen.
      die funktion datediff oä. gibt die anzahl der tage zwischen 2 datumsangaben.
      für den wochentag (Mo-So) für den start- und endetag gibts auch funktionen.
      und mit mod (7tage/woche) gibts die anzahl der wochenenden.
      ich hoffe diese hinweise reichen.

      Okay, das hatte ich mir auch überlegt für die Wochenenden. Allerdings, wie finde ich heraus, ob ein Feiertag in diesem Intervall liegt? Hilft mir da ein einfacher String-Vergleich?

      Der Yeti

      --
      Habe nun, ach! WInfo, BWL, und Mathe, Und leider auch Info!
      Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!
      Und bin so klug als wie zuvor!
      sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:[ zu:) fl:| ss:) ls:< js:|
      1. Tag Yeti.

        Allerdings, wie finde ich heraus, ob ein Feiertag in diesem Intervall liegt? Hilft mir da ein einfacher String-Vergleich?

        Naja, du hast doch Start- und Endwert der Periode. Ergo sollte sowas grundsätzlich gehen (ohne Gewähr):

        if(strtotime($start) >= strtotime($feiertag) && strtotime($ende) <= strtotime($feiertag))  
          $arbeitstage--;
        

        Siechfred

        1. Tag Yeti.

          if(strtotime($start) >= strtotime($feiertag) && strtotime($ende) <= strtotime($feiertag))

          $arbeitstage--;

            
          Jesses, natürlich andersrum:  
            
          ~~~php
          if(strtotime($start) <= strtotime($feiertag) && strtotime($ende) >= strtotime($feiertag))  
             $arbeitstage--;
          

          Siechfred

          1. Hi,

            if(strtotime($start) <= strtotime($feiertag) && strtotime($ende) >= strtotime($feiertag))

            $arbeitstage--;

              
            Danke. Das sieht gut aus. Allerdings, wie mache ich es beim Jahreswechsel? Dann müsste ich doch eigentlich die Daten aus beiden Jahren vergleichen, oder? Gut, dann läuft die Schleife halt ein zweites Mal. Dürfte nicht viel dramatischer sein. Zumindest nicht so langsam wie mein erster Trivialansatz.  
              
            Ich probier's mal aus.  
              
            Der Yeti
            
            -- 
            Habe nun, ach! [WInfo](http://www.informatik.uni-koeln.de/winfo/), BWL, und Mathe, Und leider auch Info!  
            Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!  
            Und bin so klug als wie zuvor!  
              
            [sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:\[ zu:) fl:| ss:) ls:< js:|](http://community.de.selfhtml.org/fanprojekte/selfcode.htm)
            
            1. Tag Yeti.

              Danke. Das sieht gut aus.

              Was ich noch vergessen hatte zu erwähnen ist, dass du natürlich sicherstellen musst, dass er dir nur Feiertage abzieht, die auf einen Werktag fallen, da du die Wochenenden ja schon abgezogen hast.

              Siechfred

              1. Hi,

                Was ich noch vergessen hatte zu erwähnen ist, dass du natürlich sicherstellen musst, dass er dir nur Feiertage abzieht, die auf einen Werktag fallen, da du die Wochenenden ja schon abgezogen hast.

                Ah, richtig. Danke!
                Ich glaube diese vielen Sonderfälle waren am Anfang der Grund, warum ich lieber die Schleife gemacht habe. ;-)
                Es sind auch eigentlich immer nur 3 oder 4 Tage zwischen den Daten, nur in Ausnahmefällen mal 100 oder so. Daher läuft die Schleife eigentlich nicht lange, außer eben bei 10.000-fachem Aufruf. :-)

                Der Yeti

                --
                Habe nun, ach! WInfo, BWL, und Mathe, Und leider auch Info!
                Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!
                Und bin so klug als wie zuvor!
                sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:[ zu:) fl:| ss:) ls:< js:|
                  1. Hi,

                    Das hier sieht gut aus:
                    [Augsburger Friedensfest](http://pear.php.net/manual/en/package.datetime.date-

                    Hmm, weiß nicht. Nur einmal "Germany"? Wir haben doch regional durchaus unterschiedliche Feiertage (ich sage nur [link:http://de.wikipedia.org/wiki/Augsburger_Friedensfest)).
                    Egal, ich hab's ja schon.

                    Der Yeti

                    --
                    Habe nun, ach! WInfo, BWL, und Mathe, Und leider auch Info!
                    Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!
                    Und bin so klug als wie zuvor!
                    sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:[ zu:) fl:| ss:) ls:< js:|
              2. Tag Yeti.

                Ich bin heute irgendwie zu fix :-)

                Was ich noch vergessen hatte zu erwähnen ist, dass du natürlich sicherstellen musst, dass er dir nur Feiertage abzieht, die auf einen Werktag fallen, da du die Wochenenden ja schon abgezogen hast.

                Z.B. so:

                function noWeekend($time) {  
                  if(strftime("%u", $time) == 6 || strftime("%u", $time) == 7)  
                    return False;  
                  else  
                    return True;  
                }
                

                Und dann weiter:

                if(strtotime($start) <= strtotime($feiertag) && strtotime($ende) >= strtotime($feiertag) && noWeekend(strtotime($feiertag)) )  
                  $arbeitstage--;
                

                Aber gibt's da in PEAR kein Modul für?

                Siechfred

                1. Hi,

                  Ich bin heute irgendwie zu fix :-)

                  Macht nix. :-)

                  function noWeekend($time) {

                  if(strftime("%u", $time) == 6 || strftime("%u", $time) == 7)
                      return False;
                    else
                      return True;
                  }

                    
                  Ich hab jetzt  
                  ~~~php
                    
                  if (date("w",strtotime($feiertag)) != 0 && date("w",strtotime($feiertag)) != 6 && $anfang <= $feiertag && $ende >= $feiertag)  
                     $tage--;  
                  
                  ~~~gemacht.  
                    
                  
                  > Aber gibt's da in PEAR kein Modul für?  
                    
                  Weiß ich nicht. Hatte ich vorher nicht installiert (jetzt schon), dachte aber dass ich das schnell selbst lösen könnte. Wusste nicht, woran man dabei immer denken muss.  
                  Jetzt installiere ich bestimmt kein Modul mehr, weil ich es ja inklusive Feiertagsverwaltung für die User schon fertig habe, nur eben nicht superschnell.  
                    
                  Der Yeti
                  
                  -- 
                  Habe nun, ach! [WInfo](http://www.informatik.uni-koeln.de/winfo/), BWL, und Mathe, Und leider auch Info!  
                  Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!  
                  Und bin so klug als wie zuvor!  
                    
                  [sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:\[ zu:) fl:| ss:) ls:< js:|](http://community.de.selfhtml.org/fanprojekte/selfcode.htm)
                  
      2. ja, ja, die feiertage hatte ich übersehen. diese gibts aber sicherlich irgendwo.
        am einfachsten in einer db. dann ließe sich per count() die anzahl der tage ermitteln, welche in der where bedingung zwischen start- und enddate angegeben sind.
        oder aber du hast ein (sortiertes) array mit schlüsseln, welche das datum sind. dann ließe sich das über array-funktionen machen.

        1. Hi,

          ja, ja, die feiertage hatte ich übersehen. diese gibts aber sicherlich irgendwo.
          am einfachsten in einer db. dann ließe sich per count() die anzahl der tage ermitteln, welche in der where bedingung zwischen start- und enddate angegeben sind.
          oder aber du hast ein (sortiertes) array mit schlüsseln, welche das datum sind. dann ließe sich das über array-funktionen machen.

          Ja, stehen in der DB. Allerdings sollen sie ja nicht nur für ein Jahr gelten (wie es in Excel ist), sondern ich war ein bisschen cleverer. So muss jetzt niemand jährlich die Feiertage nachpflegen, sondern man definiert sie nur einmal für jeden Standort.
          Die fixen Feiertage sind kein Problem (z.B. 01.01.), aber es gibt ja auch die beweglichen, die sind in der DB nur als Abstand zu Ostersonntag gespeichert, also z.B. +1 für Ostermontag oder -2 für Karfreitag.
          Aber da hab ich schon was Schlaues im Hinterkopf.

          Der Yeti

          --
          Habe nun, ach! WInfo, BWL, und Mathe, Und leider auch Info!
          Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!
          Und bin so klug als wie zuvor!
          sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:[ zu:) fl:| ss:) ls:< js:|
  2. Hi,
    habe jetzt die Funktion entsprechend umgestellt.
    Ergebnis: Statt 26 Sekunden nur noch 7! Das ist doch schon mal sehr gut. Ich glaube, viel besser wird's nicht.
    Daher sage ich schon mal:

    Der Yeti

    --
    Habe nun, ach! WInfo, BWL, und Mathe, Und leider auch Info!
    Durchaus studiert, mit heißem Bemühn. Da steh' ich nun, ich armer Thor!
    Und bin so klug als wie zuvor!
    sh:( fo:| ch:? rl:? br:< n4:& ie:( mo:| va:| de:[ zu:) fl:| ss:) ls:< js:|