Search code examples
phplogic

Get Possible Order Date Based On Multiple Conditions


I can't wrap my head around this particular problem.

There is a bakery, and an office that accepts orders.

Bakery is open from Monday to Sunday, it's only closed during public holidays.

Orders can be placed from Monday to Friday unless it's a public holiday i.e. the office is open during working days.

We also need to distinguish if the user managed to order goods before or after a particular time, let's say 12:00.

A few examples:

  1. It's 22.7.2022 (Friday) at 10:00 - orders can be placed for the following days Saturday(23.7), Sunday(24.7), Monday(25.7), etc.
  2. It's 22.7.2022 (Friday) at 13:00 - orders can be placed for the following days Tuesday(26.7), Wednesday(27.7), Thursday(28.7), etc.
  3. It's 20.7.2022 (Wednesday) at 10:00 - orders can be placed for the following days Thursday(21.7), Friday(22.7), Saturday(23.7), etc.
  4. It's 20.7.2022 (Wednesday) at 13:00 - orders can be placed for the following days Friday(22.7), Saturday(23.7), Sunday(24.7), etc.
  5. It's 23.7.2022 (Saturday) and 24.7.2022 (Sunday) anytime - orders can be placed for the following days Tuesday(26.7), Wednesday(27.7), Thursday(28.7), etc.
  6. It's 26.7.2022 (Monday) at 10:00 and 27.7(Tuesday) and 28.7(Wednesday) are public holidays - orders can be placed for the following days Thursday(28.7), Friday(29.7), Saturday(30.7), etc.
  7. It's 26.7.2022 (Monday) at 13:00 and 27.7(Tuesday) and 28.7(Wednesday) are public holidays - orders can be placed for the following days Friday(29.7), Saturday(30.7), Sunday(31.7), etc.

This is what I've got so far, but the code isn't working as expected.

function freeDays()
{
    return array(
        '01.01' // Den obnovy českého státu, Nový rok.
    , date('d.m', strtotime("-2 day", easter_date(date('Y')))) // Velký pátek
    , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí
    ,'01.05' // Svátek práce
    ,'08.05' // Den vítězství
    ,'05.07' // Cyrila a Metoděj
    ,'06.07' // Jan Hus
    ,'28.09' // Den české státnosti
    ,'28.10' // Vznik samostatného československého státu
    ,'17.11' // Den boje za svobodu a demokracii
    ,'24.12' // Štědrý den
    ,'25.12' // 1. svátek vánoční
    ,'26.12' // 2. svátek vánoční
    ,'31.12' // Silvestr
    );
}

function bakeryClosedDays()
{
    return array(
        '01.01' // Den obnovy českého státu, Nový rok.
    , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí
    ,'08.05' // Den vítězství
    ,'28.09' // Den české státnosti
    ,'28.10' // Vznik samostatného československého státu
    ,'17.11' // Den boje za svobodu a demokracii
    ,'25.12' // 1. svátek vánoční
    ,'26.12' // 2. svátek vánoční


    ,'23.07' // TEST
//    ,'24.07' // TEST
//    ,'25.07' // TEST
//    ,'26.07' // TEST
//    ,'28.07' // TEST
    );
}

function isFreeDay($timestamp)
{
    return in_array(date('d.m', $timestamp), freeDays());
}

function isBakeryClosed($timestamp)
{
    return in_array(date('d.m', $timestamp), bakeryClosedDays());
}

function isFriday($timestamp)
{
    return date("N", $timestamp) == 5;
}

function isDeadline($timestamp)
{
    return (int)date('H', $timestamp) >= 12;
}

function isWeekend($timestamp)
{
    return date('N', $timestamp) >= 6;
}

function isToday($timestamp)
{
    return  date('d.m.Y') == date('d.m.Y', $timestamp) ;
}

function resetHours($timestamp)
{
    return strtotime(date('Y-m-d', $timestamp));
}

function getOrderDay($timestamp, $postpone_order = false)
{
    if ($postpone_order) {
        $timestamp = strtotime("+1 day", $timestamp);
    }

    if (isWeekend($timestamp)) {
        return getOrderDay(strtotime("next Tuesday", $timestamp));
    }

    if (isFriday($timestamp) && isDeadline($timestamp)) {
        return getOrderDay(strtotime("next Tuesday", $timestamp));
    }

    if(isBakeryClosed($timestamp)) {
        return getOrderDay(strtotime("+2 day", $timestamp));
    }

    if(isFreeDay($timestamp)) {
        return getOrderDay(strtotime("+1 day", $timestamp));
    }

    if (isDeadline($timestamp)) {
        return strtotime("+2 day", $timestamp);
    }

    return $timestamp;
}


$start_timestamp = strtotime('22.07.2022 10:00:00');

print_r(date('d.m.Y H:i:s', getOrderDay($start_timestamp)));

// weekday before 12 +1 day
// weekday after 12 +2 days
// red-letter day +2 days
// saturday-sunday +2 days

Solution

  • enter image description here

    I'd like to share my own solution, which I ended up with.

    Maybe, it'll help someone in the future.

    What helped me a ton was drawing all the possible combinations in graphs, then everything became much clearer and easier.

    I think most of the code is self-explanatory, I tried to be as verbose with the function names and variables as possible.

    function publicHolidays()
    {
        return array(
            '01.01' // Den obnovy českého státu, Nový rok.
        , date('d.m', strtotime("-2 day", easter_date(date('Y')))) // Velký pátek
        , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí
        ,'01.05' // Svátek práce
        ,'08.05' // Den vítězství
        ,'05.07' // Cyrila a Metoděj
        ,'06.07' // Jan Hus
        ,'28.09' // Den české státnosti
        ,'28.10' // Vznik samostatného československého státu
        ,'17.11' // Den boje za svobodu a demokracii
        ,'24.12' // Štědrý den
        ,'25.12' // 1. svátek vánoční
        ,'26.12' // 2. svátek vánoční
        ,'31.12' // Silvestr
        );
    }
    
    function bakeryClosedDays()
    {
        return array(
            '01.01' // Den obnovy českého státu, Nový rok.
        , date('d.m', strtotime("+1 day", easter_date(date('Y')))) // Velikonoční pondělí
        ,'08.05' // Den vítězství
        ,'28.09' // Den české státnosti
        ,'28.10' // Vznik samostatného československého státu
        ,'17.11' // Den boje za svobodu a demokracii
        ,'25.12' // 1. svátek vánoční
        ,'26.12' // 2. svátek vánoční
    
    
    //    ,'19.07' // UT - TEST
    //    ,'20.07' // ST - TEST
        ,'22.07' // PA - TEST
    //    ,'23.07' // SO - TEST
    //    ,'25.07' // PO - TEST
        ,'26.07' // TEST
    //    ,'27.07' // TEST
    //    ,'25.07' // TEST
    //    ,'26.07' // TEST
    //    ,'28.07' // TEST
        );
    }
    
    function isPublicHoliday($timestamp)
    {
        return in_array(date('d.m', $timestamp), publicHolidays());
    }
    
    function isBakeryClosed($timestamp)
    {
        return in_array(date('d.m', $timestamp), bakeryClosedDays());
    }
    
    function isAfterOrderHour($timestamp)
    {
        return (int)date('H', $timestamp) >= 12;
    }
    
    function isWeekend($timestamp)
    {
        return date('N', $timestamp) >= 6;
    }
    
    function isWorkingDay($timestamp)
    {
        if (isWeekend($timestamp)) {
            return false;
        }
    
        if (isBakeryClosed($timestamp)) {
            return false;
        }
    
        if (isPublicHoliday($timestamp)) {
            return false;
        }
    
        return true;
    }
    
    function getNextWorkingDay($timestamp)
    {
        do {
            $timestamp = strtotime('+1 day', $timestamp);
        } while(!isWorkingDay($timestamp));
    
        return $timestamp;
    }
    
    function getOrderDayTimestamp($orderTimestamp)
    {
        if (isAfterOrderHour($orderTimestamp) || !isWorkingDay($orderTimestamp)) {
            $nextOrderOfficeProcessingTimestamp = getNextWorkingDay($orderTimestamp);
            $nextOrderTimestamp = $nextOrderOfficeProcessingTimestamp;
            do {
                $nextOrderTimestamp = strtotime('+1 day', $nextOrderTimestamp);
            } while(isBakeryClosed($nextOrderTimestamp));
    
            return $nextOrderTimestamp;
        }
    
        $nextOrderTimestamp = $orderTimestamp;
        do {
            $nextOrderTimestamp = strtotime('+1 day', $nextOrderTimestamp);
        } while(isBakeryClosed($nextOrderTimestamp));
    
        return $nextOrderTimestamp;
    }
    
    $orderTimestamp = strtotime('21.07.2022 10:00:00');
    printf("Chosen day | %s", date('l - d.m.Y H:i', $orderTimestamp));
    echo "\n";
    
    printf("Future order | %s", date('l - d.m.Y H:i', getOrderDayTimestamp($orderTimestamp)));
    echo "\n";
    echo "\n";
    echo "\n";
    echo "\n";
    echo "\n";
    echo "\n";
    
    
    
    var_dump(isWorkingDay($orderTimestamp));;
    
    // weekday before 12 +1 day
    // weekday after 12 +2 days
    // red-letter day +2 days
    // saturday-sunday +2 days