PHP :: Aufgabe #131

1 Lösung Lösung öffentlich

GUI-Anwendung für Feiertags- und Arbeitstageausgabe

Anfänger - PHP von hollst - 11.11.2016 um 10:23 Uhr
Schreibe eine GUI-Anwendung, die ausgehend von einem Startdatum bis zu einem (exklusiven) Enddatum alle dazwischen liegenden Feiertage in Deutschland ausgibt sowie die Anzahl der Arbeitstage, d. h. Anzahl der Tage abzüglich Sa. + So. und Feiertage, die nicht auf Sa. oder So. fallen. Das Ergebnis soll bundeslandbezogen sein (also bitte Auswahlmöglichkeit einbauen).

Optional kann man das auf Österreich und/oder die Schweiz erweitern.

Lösungen:

vote_ok
von miraja (410 Punkte) - 10.10.2017 um 15:37 Uhr
Zum Auslesen der Feiertage habe ich eine kostenfreie API namens feiertage.jarmedia.de verwendet. Die Feiertage werden dort jahresweise und abhängig vom übergegeben Bundesland ausgegeben. Dann entferne ich Feiertage die nicht in den angegebenen Zeitraum (exklusive Start- und Enddatum) fallen und errechne die Anzahl der Feiertage, wie sich die Feiertage auf Arbeitstage und Wochenenden verteilen und wie viele Arbeitstage im angegebenen Zeitraum liegen. Da ich sowohl mit der Ansprache von APIs und der DateTime-Klasse noch nicht viel Erfahrung habe, freue ich mich über jegliche Verbesserungsvorschläge.
Quellcode ausblenden PHP-Code
<?php

function validateDate($date)
{
    $d = DateTime::createFromFormat('Y-m-d', $date);
    return $d && $d->format('Y-m-d') === $date;
}

function validateState($state) {
    $states = ['bw', 'by', 'be', 'bb', 'hb', 'hh', 'he', 'mv', 'ni', 'nw', 'rp', 'sl', 'sn', 'st', 'sh', 'th',
        'national'];
    return in_array($state, $states) ? true : false;
}

/**
 * spricht API an, die Feiertage eines Jahres zurückgibt
 * @param int $year
 * @param string $state
 * @return mixed
 */
function getHolidaysOfState($year, $state)
{
    $base_url = 'http://feiertage.jarmedia.de/api/?jahr=';
    $url_part_state = 'nur_land=' . $state;
    $holidays_of_state = [];

    $page_content = json_decode(file_get_contents($base_url . $year . '&' . $url_part_state));
    foreach ($page_content as $holiday_name => $holiday) {
        $holidays_of_state[] = ['name' => $holiday_name, 'date' => $holiday->datum];
    }
    return $holidays_of_state;
}

/**
 * gibt eine Liste aller Feiertage zurück, die zwischen den angegebenen Daten liegen
 * @param DateTime $start_date
 * @param DateTime $end_date
 * @param string $state
 * @return array
 */
function getHolidaysInTimespan(DateTime $start_date, DateTime $end_date, $state)
{
    $start_year = intval($start_date->format('Y'));
    $end_year = intval($end_date->format('Y'));
    $years_diff = $end_year - $start_year;

    //Liste aller Feiertage im Jahreszeitraum (Anfangsjahr bis Endjahr)
    $holidays_in_timespan = [];
    for ($i = 0; $i <= $years_diff; $i++) {
        $year = $start_year + $i;
        foreach (getHolidaysOfState($year, $state) as $holiday) {
            $holidays_in_timespan[] = $holiday;
        }
    }

    //Entfernt Feiertage die außerhalb des Zeitraums liegen
    foreach ($holidays_in_timespan as $holiday_key => $holiday) {
        $holiday_date = DateTime::createFromFormat('Y-m-d H:i:s', $holiday['date'] . ' 00:00:00');
        if ($start_date >= $holiday_date || $holiday_date >= $end_date) {
            unset($holidays_in_timespan[$holiday_key]);
        }
    }
    return $holidays_in_timespan;
}

/**
 * gibt eine Liste aller Feiertage zurück, die zwischen den angegebenen Daten liegen und auf Arbeitstage fallen
 * @param DateTime $start_date
 * @param DateTime $end_date
 * @param string $state
 * @return array
 */
function getHolidaysOnWorkdays(DateTime $start_date, DateTime $end_date, $state)
{
    $holidays_on_workdays = getHolidaysInTimespan($start_date, $end_date, $state);

    //Entfernt Feiertage an Wochenenden aus Liste
    foreach ($holidays_on_workdays as $holiday_key => $holiday) {
        $holiday_date = DateTime::createFromFormat('Y-m-d H:i:s', $holiday['date'] . ' 00:00:00');
        $holiday_weekday = $holiday_date->format('l');
        if ($holiday_weekday === 'Saturday' || $holiday_weekday === 'Sunday') {
            unset($holidays_on_workdays[$holiday_key]);
        }
    }
    return $holidays_on_workdays;
}

/**
 * Berechnet Anzahl der Arbeitstage zwischen den angegebenen Daten
 * @param DateTime $start_date
 * @param DateTime $end_date
 * @param string $state
 * @return int
 */
function getNumWorkdaysInTimespan(DateTime $start_date, DateTime $end_date, $state)
{
    //numerische Repräsentation der Arbeitstage
    $workdays = [1, 2, 3, 4, 5];

    //Anzahl der Tage zwischen Start- und Enddatum
    $days_between_dates = $end_date->diff($start_date)->format('%a') - 1;

    //zieht Feiertage, die nicht auf Wochenenden fallen von der Anzahl der Arbeitstagen ab
    $left_over_days = $days_between_dates - count(getHolidaysOnWorkdays($start_date, $end_date, $state));

    //fängt bei einem Tag nach Startdatum an, Samstage und Sonntage von den verbleibenden Tagen abzuziehen
    $date = clone $start_date;
    $date->modify('+1 day');
    while ($date < $end_date) {
        if (!in_array($date->format('N'), $workdays)) {
            $left_over_days--;
        }
        $date->modify('+1 day');
    }
    return $left_over_days;
}

/**
 * verarbeitet den angegebenen Zeitraum und gibt einen Antwortstring zurück
 * @param string $start_date
 * @param string $end_date
 * @param string $state
 * @return string
 */
function processTimespan($start_date, $end_date, $state)
{
    $start_date = DateTime::createFromFormat('Y-m-d H:i:s', $start_date . ' 00:00:00');
    $end_date = DateTime::createFromFormat('Y-m-d H:i:s', $end_date . ' 00:00:00');

    $holiday_list = getHolidaysInTimespan($start_date, $end_date, $state);
    $num_holidays_total = count($holiday_list);
    $holiday_on_workdays_list = getHolidaysOnWorkdays($start_date, $end_date, $state);
    $num_holidays_on_workdays = count($holiday_on_workdays_list);
    $num_workdays = getNumWorkdaysInTimespan($start_date, $end_date, $state);

    //Erstellt Rückgabestring
    $message_num_holidays = 'Zwischen dem ' . $start_date->format('d.m.Y') . ' und dem ' . $end_date->format('d.m.Y');
    if ($num_holidays_total === 1) {
        $message_num_holidays .= ' liegt ' . $num_holidays_total . ' Feiertage.';
    } elseif ($num_holidays_total === 0) {
        $message_num_holidays .= ' liegen keine Feiertage.';
    } else {
        $message_num_holidays .= ' liegen ' . $num_holidays_total . ' Feiertage.';
    }

    $message_holidays = '<br/>';
    foreach ($holiday_list as $holiday) {
        $holiday_date = DateTime::createFromFormat('Y-m-d', $holiday['date']);
        $message_holidays .= $holiday_date->format('D, d.m.Y') . ': ' . $holiday['name'] . '<br/>';
    }

    $message_holiday_distribution = '';
    if ($message_num_holidays > 0) {
        $message_holiday_distribution = ' Davon fallen ' . ($num_holidays_total - $num_holidays_on_workdays) . ' auf
        Wochenenden und ' . $num_holidays_on_workdays . ' auf Arbeitstage.<br/>';
    }

    $message_num_workdays = 'Zwischen Start- und Enddatum ';
    if ($num_workdays === 1) {
        $message_num_workdays .= 'liegt ' . $num_workdays . ' Arbeitstag.<br/>';
    } elseif ($num_workdays === 0) {
        $message_num_workdays .= 'liegen keine Arbeitstage.<br/>';
    } else {
        $message_num_workdays .= 'liegen ' . $num_workdays . ' Arbeitstage.';
    }
    return $message_num_holidays . $message_holidays . $message_holiday_distribution . $message_num_workdays;
}

?>

Quellcode ausblenden HTML-Code
<!DOCTYPE html>
<html>
<head>
    <title>Arbeitstage Ermitteln</title>
</head>
<body>
    <div>
        <h1>Gib einen Zeitraum und ein Bundesland an</h1>
        <p>Diese Seite berechnet die Anzahl der Arbeitstage, die zwischen den beiden Daten liegen</p>
        <form method="get" action="">
            <label for="start_date">Anfangsdatum</label>
            <input type="date" name="start_date" id="start_date">
            <label for="end_date">Enddatum</label>
            <input type="date" name="end_date" id="end_date">
            <br/>
            <input type="radio" name="state" id="bw" value="bw">
            <label for="bw">Baden-Württemberg</label>
            <br/>
            <input type="radio" name="state" id="by" value="by">
            <label for="by">Bayern</label>
            <br/>
            <input type="radio" name="state" id="be" value="be">
            <label for="be">Berlin</label>
            <br/>
            <input type="radio" name="state" id="bb" value="bb">
            <label for="bb">Brandenburg</label>
            <br/>
            <input type="radio" name="state" id="hb" value="hb">
            <label for="hb">Bremen</label>
            <br/>
            <input type="radio" name="state" id="hh" value="hh">
            <label for="hh">Hamburg</label>
            <br/>
            <input type="radio" name="state" id="he" value="he">
            <label for="he">Hessen</label>
            <br/>
            <input type="radio" name="state" id="mv" value="mv">
            <label for="mv">Mecklenburg-Vorpommern</label>
            <br/>
            <input type="radio" name="state" id="ni" value="ni">
            <label for="ni">Niedersachsen</label>
            <br/>
            <input type="radio" name="state" id="nw" value="nw">
            <label for="nw">Nordrhein-Westfalen</label>
            <br/>
            <input type="radio" name="state" id="rp" value="rp">
            <label for="rp">Rheinland-Pfalz</label>
            <br/>
            <input type="radio" name="state" id="sl" value="sl">
            <label for="sl">Saarland</label>
            <br/>
            <input type="radio" name="state" id="sn" value="sn">
            <label for="sn">Sachsen</label>
            <br/>
            <input type="radio" name="state" id="st" value="st">
            <label for="st">Sachsen-Anhalt</label>
            <br/>
            <input type="radio" name="state" id="sh" value="sh">
            <label for="sh">Schleswig-Holstein</label>
            <br/>
            <input type="radio" name="state" id="th" value="th">
            <label for="th">Thüringen</label>
            <br/>
            <input type="radio" name="state" id="national" value="national">
            <label for="national">Bundesweit</label>
            <br/>
            <br/>
            <input type="submit" value="Berechnen">
            <br/>
            <br/>
        </form>
    </div>
</body>
</html>

Quellcode ausblenden PHP-Code
<?php

if (!empty($_GET['start_date']) && !empty($_GET['end_date']) && !empty($_GET['state'])) {
    $start_date = $_GET['start_date'];
    $end_date = $_GET['end_date'];
    $state = $_GET['state'];
    if (validateDate($start_date) && validateDate($end_date)) {
        $start_date = DateTime::createFromFormat('Y-m-d H:i:s', $start_date . ' 00:00:00');
        $end_date = DateTime::createFromFormat('Y-m-d H:i:s', $end_date . ' 00:00:00');
        if ($start_date < $end_date) {
            if (validateState($state)) {
                echo(processTimespan($_GET['start_date'], $_GET['end_date'], $_GET['state']));
            } else {
                echo('Bitte gib einen validen Bundestaat an.');
            }
        } else {
            echo('Das Anfangsdatum muss kleiner sein als das Enddatum.');
        }

    } else {
        echo('Bitte gib ein valides Datum ein.');
    }
}
1801066

Du scheinst einen AdBlocker zu nutzen. Ich würde mich freuen, wenn du ihn auf dieser Seite deaktivierst und dich davon überzeugst, dass die Werbung hier nicht störend ist.