Rolf B: Darstellung/ Ausgabe von weiteren Einträge abhängig machen

Beitrag lesen

Hallo Bernd,

for ($i=0; $i<count($termine); $i++) und if ($i+1 <count($termine))

es gab einen Grund, warum ich Dir schrieb, Du solltest bei $i=1 beginnen und dann die Einträge $i-1 und $i verwenden. Dadurch wird genau diese Abfrage überflüssig. Freie Zeiten zu Beginn und am Ende fragt man besser separat ab.

Prinzipiell gibt es zwei „richtige“ Ansätze.

Entweder
du beginnst bei 0, und läufst bis count($termine)-1
und verwendest dann $i und $i+1
Oder
du beginnst bei 1, und läufst bis count($termine)
und verwendest dann $i-1 und $i

Welche Variante du nimmst, ist letztlich egal. Für das Zeitfenster am Ende braucht man eh count($termine)-1, da kann man die ENTWEDER Variante auch nehmen.

Und ja, richtig, für überlappende Termine musst Du prüfen ob
$termine[$i-1]['bis'] >= $termine[$i]['von'] gilt. Wenn ja, ist keine Lücke da.

Für den Zeitraum am Anfang:

$Anfang = "9:00";
$Ende = "18:00";
$Da = "";
$lastI = count($termine) - 1;
// Gar kein Termin da?
if ($lastI < 0)
{
   $Da = $Anfang . " bis " . $Ende;
}
else
{
   if ($Anfang < $termine[0]['t_von'])
   {
      $Da .= $Anfang . " bis " . $termine[0]['t_von'];
   }
   for ($i=0; $i < $lastI; $i++)
   {
      if ($termine[$i]['t_bis'] < $termine[$i+1]['t_von'])
      {
         $Da .= $termine[$i]['t_bis'] . " bis " . $termine[$i+1]['t_von'] . "<br>";
      }
   }
   if ($termine[$lastI]['t_bis'] < $Ende)
   {
      $Da .= $termine[$lastI]['t_bis'] . " bis " . $Ende;
   }
}

echo "Zeiten: " . $Da;

patsch Rolf, Du Depp.

Mir fällt gerade auf, dass es auch viel kürzer geht. Man kann sich einfach nur die Endezeit des vorigen Termins merken, und eliminiert mit zwei Tricks die Sonderfälle für die Randzeiten sowie die Abfrage auf "es gibt heute keine Termine". Dann kann man sogar wieder foreach verwenden. Wenn Du diese Variante verstehst, verwende sie 😀. Aber nur dann!!!

$Anfang = "09:00";
$Ende = "18:00";
$Da = "";

// Anfang als Ende des letzen Termins setzen
$vorigesBis = $Anfang;
// Pseudotermin hinzufügen für Ende der Arbeitszeit
$termine[] = [ 't_von' => $Ende, 't_bis' => 'xxxxx' ];

// Und jetzt über alle Termine iterieren.
foreach ($termine as $termin)
{
   if ($vorigesBis < $termin['t_von'])
   {
      $Da .= $vorigesBis . " bis " . $termin['t_von'] . "<br>";
   }
   if ($termin['t_bis'] > $vorigesBis)   // Falls ein Monstertermin andere überdeckt
   {
      $vorigesBis = $termin['t_bis'];
   }
}

echo "Zeiten: <br>" . $Da;

All diese Varianten sind für Datenmüll anfällig. Wenn Du einen Termin hast, der andere Termine komplett überdeckt (Termin 1 von 10-18 Uhr, Termin 2 von 12-13 Uhr), dann wirst Du 13-18 Uhr als Freizeit bekommen. Deswegen diese "Anti-Monster Maßnahme": lass $vorigesBis nur wachsen, aber nie kleiner werden.

So isses beim Programmieren - man macht und macht und auf einmal geht's bling und man sieht eine viel kompaktere Lösung. Ob sie einfacher ist, bleibe dahingestellt. Durch das Nachführen von $lastEnd entsteht eine höhere Komplexität, weil sich ein Schleifendurchlauf auf ein Ergebnis aus dem Durchlauf davor beziehen muss.

Und dann kommt so ein böser Testfall - wie der von Dir vorher gepostete - und macht den ursprünglichen Plan auch noch kaputt.

Rolf

--
sumpsi - posui - clusi