Skip to content

Instantly share code, notes, and snippets.

@marcus-at-localhost
Last active November 13, 2022 13:07
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcus-at-localhost/2698a72dfcabab999a86 to your computer and use it in GitHub Desktop.
Save marcus-at-localhost/2698a72dfcabab999a86 to your computer and use it in GitHub Desktop.
Delivery date calculation - ship till a certain time, add n days for delivery and detect weekends DateTime Class in PHP
<?php
// new date/time object
$date = new DateTime('now');
// set order time to a Saturday, 2 pm
$date->modify('next sat 14:00');
// orders are taken in till 15 minutes before 2pm
// http://php.net/manual/de/datetime.formats.relative.php
$order_till = new DateTime('front of 14');
// preserve original date
$date_min = clone $date;
// use interval
//$date_min->add(new DateInterval("P1D"));
// orders after 1:45 pm are getting shipped the next day
if($date > $order_till)
{
$date_min->modify('1 weekdays');
}
// if it's on a weekend then it gets shipped on monday
if($date_min->format('N') >= 6){
$date_min->modify('next monday');
}
// add delivery time
$date_min->modify('3 weekdays');
var_dump('Ordered:', $date->format('l jS \of F Y H:i:s'));
var_dump('Delivery:', $date_min->format('l jS \of F Y H:i:s'));
@aiphee
Copy link

aiphee commented Mar 29, 2022

My take with Yasumi lib to take holidays in account

    public function getDateForWorkdaysAdded(DateTime $startDate, int $daysToAdd): DateTime
    {
        $countryClassName = match($this->countryCode) {
            'cz' => CzechRepublic::class,
        }; // Will throw when country not configured

        $holidayYearInstances = [];

        $dateToReturn = clone $startDate;

        while ($daysToAdd > 0) {
            $dateToReturn->modify('+1 day');

            $year = (int) $dateToReturn->format('Y');
            if (!isset($holidayYearInstances[$year])) { // Make sure we have Yasumi for current year
                $holidayYearInstances[$year] = Yasumi::create($countryClassName, $year);
            }

            if ($holidayYearInstances[$year]->isWorkingDay($dateToReturn)) {
                $daysToAdd--; // Not weekend nor holiday. Cool, continue with one day less to process
            }
        }

        return $dateToReturn;
    }
public function testGetDateForWorkdaysAdded(): void
    {
        // 22.12.2022 thu       order created
        // 23.12.2022 fri
        // 24.12.2022 sat       weekend & cz holiday
        // 25.12.2022 sun       weekend & cz holiday
        // 26.12.2022 mon       cz holiday
        // 27.12.2022 tue
        // 28.12.2022 wed
        // 29.12.2022 thu
        // 30.12.2022 fri
        // 31.12.2022 sat       weekend
        // 01.01.2023 sun       weekend & cz holiday
        // 02.01.2023 mon       order + 6 days => delivery


        $deliveryDate = $this->dateHelper->getDateForWorkdaysAdded(new \DateTime('2022-12-22'), 6);
        self::assertSame($deliveryDate->format('Y-m-d'), '2023-01-02');
    }

@marcus-at-localhost
Copy link
Author

marcus-at-localhost commented Apr 11, 2022

Thanks @aiphee for mentioning https://github.com/azuyalabs/yasumi, that deals with holidays!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment