Jump to content

Easy Forecast Delivery Day code


WFP
Go to solution Solved by Barand,

Recommended Posts

Hi all - I've adapted & made some basic code to forecast a delivery date for my customers but needs a little refinement - can you help?

Goals & Rules
> All Sat, All Sunday & Friday after 2pm = orders will arrive Tuesday (shipped Monday and Arrive Tuesday)
> Monday - Friday orders before 2pm will arrive the next day (posted on 'd' arrive d+1 includes Sat).
> Monday - Thursday orders after 2pm will arrive in 2 days (posted on 'd+1' and arrive d+2)
 

Feature to be added

> Bank Holidays (enter an array of all bank holiday dates upfront which will extend the delivery as per the above rules)

> My current server time does not seem to recoginse changes in GMT & BST. So, when the UK is in GMT its fine (2pm = 2pm) but when we move to BST the time is 3pm but the code is reading 2pm as server looks like its still in GMT. How can this be set automatically to the correct time in the UK without editing the code for BST / GMT every time.

Code so Far

	  if(preg_match('%(Sat|Sun)%', date('D'))){
    $next_working_day = date('D dS M', strtotime('next Tuesday'));
}
	  else{
if (date('H') < 14) {
		  $next_working_day = date('D dS M', strtotime('+1 day'));
}
/* --for late friday orders going Mon-- */ 		  
		  else{
	  if(preg_match('%(Fri)%', date('D'))){

			  $next_working_day = date('D dS M', strtotime('next Tuesday'));
	  }
			  else {$next_working_day = date('D dS M', strtotime('+2 day'));}
	}
	  }		
			  echo $next_working_day;
			  print '</strong></p><hr>';
  }

 

 

Edited by WFP
Link to comment
Share on other sites

Check your default timezone setting in your php.ini file. Sounds like it's set to UTC or GMT instead of Europe/London.

You can check with

echo date_default_timezone_get();


 

$now = new DateTime();

// using default timezone
echo $now->format('H:i:s T') . '<br>';       // 17:05:29 BST    

$now->setTimezone(new DateTimeZone('UTC'));
echo $now->format('H:i:s T') . '<br>';       // 16:05:29 UTC

 

Link to comment
Share on other sites

1 hour ago, WFP said:

enter an array of all bank holiday dates upfront

No need to do that when you can calculate them...

function bankHols($yr)
{
    // CALC PUBLIC HOLS FOR $yr
    $hols = array();
    $newyr = "$yr-01-01";
    switch (date('w', strtotime($newyr))) {
        case 6:
            $newyr = "{$yr}-01-03";
            break;
        case 0:
            $newyr = "{$yr}-01-02";
            break;
    }
    $hols['New Year'] = $newyr;
    
    $easter = easter_date($yr);
    $hols['Easter'] = array(date('Y-m-d', strtotime('-2 days', $easter)),
                date('Y-m-d', strtotime('+1 days', $easter)));
                
    $mayday = (new DateTime("first monday of may $yr"))->format('Y-m-d');
    $hols['May Day'] = $mayday;
    
    $sbank = (new DateTime("last monday of may $yr"))->format('Y-m-d');
    $hols['Spring Bank'] = $sbank;
    
    $abank = (new DateTime("last monday of august $yr"))->format('Y-m-d');
    $hols['August Bank'] = $abank;
    
    $x1 = "$yr-12-25";
    $x2 = "$yr-12-26";
    switch (date('w', strtotime($x1))) {
        case 5:
            $x2 = "$yr-12-28";
            break;
        case 6:
            $x1 = "$yr-12-27";
            $x2 = "$yr-12-28";
            break;
        case 0:
            $x1 = "$yr-12-26";
            $x2 = "$yr-12-27";
            break;
    }
    $hols['Christmas'] = array($x1,$x2);
    
    return $hols;
}

$holidays = bankHols(2021);

 

  • Like 1
Link to comment
Share on other sites

ok great yes server was set in UTC, its on wordpress and even with settings set to london it was still returning UTC.

So i added before my script the below which works fine now so 1 problem fixed

date_default_timezone_set("Europe/London");

Ref the bank hols Amazing little tip there, spoon feeding abit here but im still learning at my limits

- how can i integrate your function into my initial loop?

 

p.s. I am also from cheshire UK! :D

Edited by WFP
Link to comment
Share on other sites

  • Solution
4 hours ago, WFP said:

- how can i integrate your function into my initial loop?

I'd revise the function so it just gave a plain array of dates, then nudge the delivery by a day if the due date is the holiday array.

So array is ...

Array
(
    [0] => 2021-01-01
    [1] => 2021-04-02
    [2] => 2021-04-05
    [3] => 2021-05-03
    [4] => 2021-05-31
    [5] => 2021-08-30
    [6] => 2021-12-25
    [7] => 2021-12-26
    [8] => 2021-12-27
    [9] => 2021-12-28
)

My solution: (If you don't want to be spoon-fed, ignore)

$hols = bankHols(date('Y'));
$test_dates = [ '2021-08-30 14:00', 
                '2021-08-30 14:01',
                '2021-08-31 14:00',
                '2021-08-31 14:01',
                '2021-09-01 14:00',
                '2021-09-01 14:01',
                '2021-09-02 14:00',
                '2021-09-02 14:01',
                '2021-09-03 14:00',
                '2021-09-03 14:01',
                '2021-09-04 14:00',
                '2021-09-04 14:01',
                '2021-09-05 14:00',
                '2021-09-05 14:01',
                
                '2021-03-30 14:00', 
                '2021-03-30 14:01',
                '2021-03-31 14:00',
                '2021-03-31 14:01',
                '2021-04-01 14:00',
                '2021-04-01 14:01',
                '2021-04-02 14:00',
                '2021-04-02 14:01',
                '2021-04-03 14:00',
                '2021-04-03 14:01',
                '2021-04-04 14:00',
                '2021-04-04 14:01',
                
                '2021-12-23 14:00',
                '2021-12-23 14:01',
                '2021-12-24 14:00',
                '2021-12-24 14:01'
              ];

echo '<pre>';              
foreach ($test_dates as $d) {
    $ordered = new dateTime($d);
    echo 'Ordered: ' . $ordered->format('D d M g:i a') ;
    
    $del = deliveryDate($ordered, $hols);
    echo ' &mdash; Delivery: ' . $del->format('D') . '<br>'; 
}
echo '</pre>';              



function deliveryDate($ordered, $hols)
{
    $delivery = clone $ordered;

    if ($delivery->format('H:i') > '14:00') {                   // if it's after 2pm. treat is as the next day
        $delivery->modify('+1 day');
    }
    if (in_array($delivery->format('w'), [0,6])) {              // if it's Sat or Sun, treat it as Monday
        $delivery->modify('next monday');
    }
    do {                                                        // add a day for delivery until the date isn't a holiday.
        $delivery->modify('+1 day');
    } while (in_array($delivery->format('Y-m-d'), $hols));
    
    return $delivery;
}
 
function bankHols($yr)
{
    // CALC PUBLIC HOLS FOR $yr
    $dates = array();
    $newyr = "$yr-01-01";
    switch (date('w', strtotime($newyr))) {
        case 6:
            $newyr = "{$yr}-01-03";
            break;
        case 0:
            $newyr = "{$yr}-01-02";
            break;
    }
    $dates[] = $newyr;
    
    $easter = easter_date($yr);
    array_push($dates, date('Y-m-d', strtotime('-2 days', $easter)),  date('Y-m-d', strtotime('+1 days', $easter)));
               
    $mayday = (new DateTime("first monday of may $yr"))->format('Y-m-d');
    $dates[] = $mayday;
    
    $sbank = (new DateTime("last monday of may $yr"))->format('Y-m-d');
    $dates[] = $sbank;
    
    $abank = (new DateTime("last monday of august $yr"))->format('Y-m-d');
    $dates[] = $abank;
    
    $x1 = "$yr-12-25";
    $x2 = "$yr-12-26";
    array_push($dates, $x1, $x2);
    switch (date('w', strtotime($x1))) {
        case 5:
            $x2 = "$yr-12-28";
            break;
        case 6:
            $x1 = "$yr-12-27";
            $x2 = "$yr-12-28";
            break;
        case 0:
            $x1 = "$yr-12-26";
            $x2 = "$yr-12-27";
            break;
    }
    array_push($dates, $x1, $x2);
    
    return $dates;
}

Edited by Barand
Link to comment
Share on other sites

Be aware that on Friday 3 June, 2022 there is an extra "Jubilee" bank holiday for that year only and the May 30 (Monday) spring bank holiday moves to the following Thursday (June 2).

After the line $hols = bankHols(date('Y')); add

    // Adjust for 2022 only
    $spring = array_search('2022-05-30', $hols);
    if ($spring) {
        $hols[$spring] = '2022-06-02';    // revise date
        $hols[] = '2022-06-03';           // add Jubilee hol
    }

 

Edited by Barand
Link to comment
Share on other sites

hi there - after a few hours of trying tonight I am struggling to integrate the code for my final result of outputting the code as

Add to Basket now for FREE Delivery to you (est.) : Fri 03rd Sep

So i assume I dont need the 'test dates' var and I can instead use the $dates but I'm missing something to link them together as below it outputs

Add to Basket now for FREE Delivery to you (est.) :           (<-nothing returned)

$hols = bankHols(date('Y'));
 
foreach ($dates as $d) {
    $ordered = new dateTime($d);
    $del = deliveryDate($ordered, $hols);
}

function deliveryDate($ordered, $hols)
{
    $delivery = clone $ordered;

    if ($delivery->format('H:i') > '14:00') {                   // if it's after 2pm. treat is as the next day
        $delivery->modify('+1 day');
    }
    if (in_array($delivery->format('w'), [0,6])) {              // if it's Sat or Sun, treat it as Monday
        $delivery->modify('next monday');
    }
    do {                                                        // add a day for delivery until the date isn't a holiday.
        $delivery->modify('+1 day');
    } while (in_array($delivery->format('Y-m-d'), $hols));
    
    return $delivery;
}
 
function bankHols($yr)
{
    // CALC PUBLIC HOLS FOR $yr
    $dates = array();
    $newyr = "$yr-01-01";
    switch (date('w', strtotime($newyr))) {
        case 6:
            $newyr = "{$yr}-01-03";
            break;
        case 0:
            $newyr = "{$yr}-01-02";
            break;
    }
    $dates[] = $newyr;
    
    $easter = easter_date($yr);
    array_push($dates, date('Y-m-d', strtotime('-2 days', $easter)),  date('Y-m-d', strtotime('+1 days', $easter)));
               
    $mayday = (new DateTime("first monday of may $yr"))->format('Y-m-d');
    $dates[] = $mayday;
    
    $sbank = (new DateTime("last monday of may $yr"))->format('Y-m-d');
    $dates[] = $sbank;
    
    $abank = (new DateTime("last monday of august $yr"))->format('Y-m-d');
    $dates[] = $abank;
    
    $x1 = "$yr-12-25";
    $x2 = "$yr-12-26";
    array_push($dates, $x1, $x2);
    switch (date('w', strtotime($x1))) {
        case 5:
            $x2 = "$yr-12-28";
            break;
        case 6:
            $x1 = "$yr-12-27";
            $x2 = "$yr-12-28";
            break;
        case 0:
            $x1 = "$yr-12-26";
            $x2 = "$yr-12-27";
            break;
    }
    array_push($dates, $x1, $x2);
    
    return $dates;
}

echo 'Add to Basket now for FREE Delivery to you (est.) : ' . $delivery ;

 

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.