1

I want to show an estimated delivery time in my shop. If a customer orders before 4pm, he gets his order the next day. But if the order is on a friday or on the weekend, he gets the order on the next monday.

That all works fine. But I need to add some holidays like christmas, new year and local holidays based on a state in my country.

I found a solution to identify the fixed and flexible (like easter) holidays in my state.

But I don't know how to work with them in the current function. If an order is placed before one of these holidays I need to move the future date some days ahead.

Here's the current code (based on this code):

date_default_timezone_set( 'Europe/Berlin' );

$current_year   = date('Y');
$next_year      = date('Y', strtotime( $current_year." + 1 year" ));

// Holidays
$neujahr        = date('d.m.Y',strtotime(date($next_year.'-01-01')));
$ostern         = date('d.m.Y', easter_date($current_year));
$karfreitag     = date( "l jS F", strtotime( $ostern." - 2 days" ) );
$ostermontag    = date( "l jS F", strtotime( $ostern." + 1 days" ) );
$tagderarbeit   = date('d.m.Y',strtotime(date('Y-05-01')));
$himmelfahrt    = date( "l jS F", strtotime( $ostern." + 39 days" ) );
$pfingstmontag  = date( "l jS F", strtotime( $ostern." + 50 days" ) );
$fronleichnam   = date( "l jS F", strtotime( $ostern." + 60 days" ) );
$einheit        = date('d.m.Y',strtotime(date('Y-10-03')));
$allerheiligen  = date('d.m.Y',strtotime(date('Y-11-01')));
$weihnachten1   = date('d.m.Y',strtotime(date('Y-12-25')));
$weihnachten2   = date('d.m.Y',strtotime(date('Y-12-26')));

// if FRI/SAT/SUN delivery will be MON
if ( date( 'N' ) >= 5 ) {
  $del_day = date( "l jS F", strtotime( "next monday" ) );
  $order_by = "Monday";
}

// if MON/THU after 4PM delivery will be TOMORROW
elseif ( date( 'H' ) >= 16 ) {
  $del_day = date( "l jS F", strtotime( "tomorrow" ) );
  $order_by = "tomorrow";
}

// if MON/THU before 4PM delivery will be TODAY
else {
  $del_day = date( "l jS F", strtotime( "today" ) );
  $order_by = "today";
}

$html = "<br><div class='woocommerce-message' style='clear:both'>Order by 4PM {$order_by} for delivery on {$del_day}</div>";

echo $html;
Cray
  • 5,307
  • 11
  • 70
  • 166
  • 1
    I think you will find your answer here https://stackoverflow.com/a/14907662/3623080 – gael Jul 13 '20 at 09:29
  • Thanks, I found a way to get the holidays of my state. But I don't know how to work with them in the current function. If an order is placed before one of these holidays I need to move the future date some days ahead. – Cray Jul 13 '20 at 12:37

1 Answers1

1

The working method you are currently applying can work with multiple different if / else statements to check all conditions, so I prefer a different approach.

It goes as follows

  1. As of today date 8 possible delivery dates are generated (expl: today = 14/07/2020, possible dates are 14, 15, 16, 17, 18, 19, 20 & 21/07/2020
  2. If today is already after 4 pm, the date of today expires (14/07/2020)
  3. Less than 4 pm but a Friday, Saturday or Sunday, remove date
  4. Then remove the (other) dates from the weekend: friday, saturday & sunday (17, 18, 19/07/2020)
  5. Then all holidays (if any) are filtered out of the result
  6. In the last step, the first value in the result is used and shown in the output message.

  • Note: It is easy to test by adjusting $today = date( 'd.m.Y' ); values ​​to any date in the future, like $today = date( '25.12.2024' ); which would return
    • Delivery on Monday 30th December
    • 25, 26 = holidays. 27, 28 & 29/12/2024 = friday, saturday & sunday
date_default_timezone_set( 'Europe/Berlin' );

// Today
$today = date( 'd.m.Y' );

// Possible delivery dates from today
for ( $i = 0; $i <= 7; $i++) {
    $possible_delivery_dates[] = date( 'd.m.Y', strtotime( $today . '+' . $i . 'days' ) ); 
}

// Today ?
if ( date( 'H', strtotime( $today ) ) >= 16 ) {
    // Today NOT possible
    unset( $possible_delivery_dates[0] );
} elseif ( date( 'N', strtotime( $today ) ) >= 5 ) {
    // Today (weekend) NOT possible
    unset( $possible_delivery_dates[0] );
}

// Next Fri, Sat & Sun
$next_friday   = date( 'd.m.Y', strtotime( $today . 'next friday' ) );
$next_saturday = date( 'd.m.Y', strtotime( $today . 'next saturday' ) );
$next_sunday   = date( 'd.m.Y', strtotime( $today . 'next sunday' ) );

// Remove next fri, sat & sun
$possible_delivery_dates = array_diff( $possible_delivery_dates, [ $next_friday, $next_saturday, $next_sunday ] );

// Current & next year
$current_year  = date( 'Y', strtotime( $today ) );
$next_year     = date( 'Y', strtotime( $today . '+ 1 year' ));

// Holidays
$neujahr       = date( 'd.m.Y', strtotime( date( $next_year . '-01-01' ) ) );
$ostern        = date( 'd.m.Y', easter_date( $current_year ) );
$karfreitag    = date( 'd.m.Y', strtotime( $ostern . '- 2 days' ) );
$ostermontag   = date( 'd.m.Y', strtotime( $ostern . '+ 1 days' ) );
$tagderarbeit  = date( 'd.m.Y', strtotime( date( $current_year . '-05-01') ) );
$himmelfahrt   = date( 'd.m.Y', strtotime( $ostern . '+ 39 days' ) );
$pfingstmontag = date( 'd.m.Y', strtotime( $ostern . '+ 50 days' ) );
$fronleichnam  = date( 'd.m.Y', strtotime( $ostern . '+ 60 days' ) );
$einheit       = date( 'd.m.Y', strtotime( date( $current_year . '-10-03' ) ) );
$allerheiligen = date( 'd.m.Y', strtotime( date( $current_year . '-11-01' ) ) );
$weihnachten1  = date( 'd.m.Y', strtotime( date( $current_year . '-12-25' ) ) );
$weihnachten2  = date( 'd.m.Y', strtotime( date( $current_year . '-12-26' ) ) );

// Holidays (array)
$holidays = array( $neujahr, $ostern, $karfreitag, $ostermontag, $tagderarbeit, $himmelfahrt, $pfingstmontag, $fronleichnam, $einheit, $allerheiligen, $weihnachten1, $weihnachten2 );

// Remove holidays
$possible_delivery_dates = array_diff( $possible_delivery_dates, $holidays );

// First value
$first_val = reset( $possible_delivery_dates );

$html = 'Delivery on ' . date( 'l jS F', strtotime( $first_val ) );

echo $html;
7uc1f3r
  • 28,449
  • 17
  • 32
  • 50
  • Thank you! That is a great answer. I just don't get how to add a date range to that. If the first possible date is one day before christimas and I want to say that the order could take 3 days, I want to show 23.12.2020 as first date and 29.12.2020 as last date. Not the 26.12.2020. I tried this `date( 'l jS F', strtotime( $first_val . '+1 day'));` but that doesn' take the holiday into account. – Cray Jul 14 '20 at 07:21
  • What dates are involved with this exception? is it only about 23/12? Does it come down to: if the current delivery date (23/12) + 3 days equals a holiday (26/12), that the date (holiday) is automatically extended by 3 days (29/12)? – 7uc1f3r Jul 14 '20 at 17:40
  • Yes, the last one if I understand it correctly. We can’t deliver on holidays. Therefore these days needs to be excluded. – Cray Jul 14 '20 at 17:43
  • do you mean this? http://sandbox.onlinephpfunctions.com/code/c6c976e310ab7721c5a31fa42c34cba35e4f81fe (press 'execute code') – 7uc1f3r Jul 14 '20 at 18:02
  • This is looking good. Will check it in a minute. I think that‘s it. Thank you! – Cray Jul 14 '20 at 18:04
  • As I understand it now, It's always +3 days after a holiday, right? Even if there it's a single day, right? Is there a way to exclude the dates from `$holidays` from the possible dates in `$last_date`? – Cray Jul 15 '20 at 07:22
  • Yes, this is currently the case in the new example, I understood that this was the intention. `$possible_delivery_dates` is currently using the first available date. Holidays and weekends are however excluded in this array, so you could use the 2nd possible date in that array, as this will not necessarily be the day after. So it depends on what you want exactly and whether to add any exceptions with an if / else condition. It helps to print the array of possible dates after each step (during debugging) to better understand what the code is doing at what time. – 7uc1f3r Jul 15 '20 at 07:52