Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save NigelDorning/e2f8ba49ac255e9ab346a16bafaace63 to your computer and use it in GitHub Desktop.
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
<?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