Last active
April 29, 2022 19:32
-
-
Save NigelDorning/e2f8ba49ac255e9ab346a16bafaace63 to your computer and use it in GitHub Desktop.
Calculates the date when adding days excluding weekends and bank holidays in England and Wales
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Checks to see if a given date is a bank holiday in the UK | |
* | |
* 1. Set the current year | |
* 2. Get the bank holidays in the UK | |
* 3. Parse out the bank holidays in the UK that are within the current year | |
* 4. Check to see if the if $check_date is within the current years bank holidays | |
* 4.1 Return true if it is | |
* 4.2 Return false if it is not | |
* | |
* @param string $check_date | |
* @return void | |
*/ | |
function check_if_date_is_bank_holiday($check_date) | |
{ | |
// Set current year | |
$year = (new DateTime('today'))->format('Y'); | |
// Get the bank holidays in the UK | |
$json = file_get_contents('https://www.gov.uk/bank-holidays.json'); | |
// Convert JSON data into associative array and get the date column from sub arrays to create array of dates | |
$event_years = array_column(json_decode($json, true)['england-and-wales']['events'], 'date'); | |
// Filter through the $event_years array and get only the years that start with the current year e.g. 2022 | |
$current_year_events = array_filter($event_years, fn($event_year) => str_starts_with($event_year, $year)); | |
// Return boolean whether $check_date is in $current_year_events | |
return in_array($check_date, $current_year_events); | |
} | |
/** | |
* Calculates the date, excluding weekends and UK bank holidays. | |
* | |
* 1. Set the current day | |
* 2. Perform a loop for the number of days passed to the function | |
* 3. Check to see which day of the week the current date is | |
* 3.1 If 5 (Friday) then add 3 days to exclude the weekend and get the following Monday | |
* 3.2 If 6 (Saturday) then add 2 to exclude Sunday and get the upcoming Monday | |
* 3.3 Otherwise add 1 day to the current date and continue the loop | |
* | |
* @param integer $days | |
* @param boolean $include_current_day | |
* @return DateTime | |
*/ | |
function calculate_date($days, $include_current_day = true) | |
{ | |
// Set the current date | |
$date = new DateTime('today'); | |
do { | |
// Check to see whether to include the current day to skip the first iteration modifying $date | |
if ($include_current_day) { | |
// Set $include_current_day so the loop can modify $date | |
$include_current_day = false; | |
} else { | |
// Check to see which day of the week the current date is and days to current day | |
$add_days = match ($date->format('N')) { | |
'5' => 3, | |
'6' => 2, | |
default => 1 | |
}; | |
// Check to see if the current day is a bank holiday and add any days to current day | |
if (check_if_date_is_bank_holiday($date->format('Y-m-d'))) { | |
$add_days++; | |
} | |
// Add days to date | |
$date->modify('+' . $add_days . ' day'); | |
} | |
// Decrement days so we can eventually break from the loop | |
$days--; | |
} while ($days > 0); | |
// Return the calculate date | |
return $date; | |
} | |
print_r(calculate_date(13)); | |
/** | |
* Example data output | |
* | |
* Next bank holiday: 02/05/22 | |
* Current date: 29/04/2022 | |
* | |
* Running calculate_date(5) should give us 06/05/22 | |
* skipping the weekend (30/05/22 & 01/05/2022) and skipping the | |
* bank holiday (02/05/22) | |
* | |
* Running calculate_date(5, false) should give us 09/05/22 | |
* skipping the both weekends (30/05/22 & 01/05/2022) & (07/05/22 & 08/05/2022) | |
* and skipping the bank holiday (02/05/22) | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment