Created
December 11, 2018 21:05
-
-
Save ranskills/50c3d5e0cfcda3c70b166f625afd706b to your computer and use it in GitHub Desktop.
Calculates the next or prior business days(s) factoring in holidays
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 | |
class BusinessCalendar | |
{ | |
private $debugMessage; | |
private $debug = false; | |
public function __construct($debug = false) | |
{ | |
$this->debug = $debug; | |
} | |
public function setDebug($debug = true) | |
{ | |
$this->debug = $debug; | |
} | |
public function getNextBusinessDays($date, $workingDays, $holidays, $numDays) | |
{ | |
$days = $this->getBusinessDays($date, $workingDays, $holidays, true, $numDays); | |
$this->debugMessage = sprintf( | |
'The next %d business after %s are %s', | |
$numDays, | |
$this->formatDate($date), | |
implode(', ', $this->formatDate($days, true)) | |
); | |
$this->printDebugMessage(); | |
return $days; | |
} | |
public function getPriorBusinessDays($date, $workingDays, $holidays, $numDays) | |
{ | |
return $this->getBusinessDays($date, $workingDays, $holidays, false, $numDays); | |
} | |
public function getBusinessDaysForAPeriod($startDate, $endDate, $workingDays, $holidays) | |
{ | |
$days = []; | |
$day = $startDate; | |
while ($day < $endDate) { | |
$day = $this->getTradingDate($day, $workingDays, $holidays, true); | |
$days[] = $day; | |
} | |
$this->debugMessage = sprintf( | |
'There are %d business day(s) between %s and %s which are %s', | |
count($days), | |
$this->formatDate($startDate), | |
$this->formatDate($endDate), | |
implode(', ', $this->formatDate($days, true)) | |
); | |
$this->printDebugMessage(); | |
return $days; | |
} | |
private function printDebugMessage() | |
{ | |
if (!$this->debug) { | |
return; | |
} | |
echo $this->debugMessage.PHP_EOL.PHP_EOL; | |
} | |
public function getNextBusinessDay($date, $workingDays, $holidays) | |
{ | |
$day = $this->getTradingDate($date, $workingDays, $holidays, true); | |
// \033[1;32m | |
$this->debugMessage = sprintf( | |
"The next business day after %s is %s", | |
$this->formatDate($date), | |
$this->formatDate($day, true) | |
); | |
$this->printDebugMessage(); | |
return $day; | |
} | |
public function getPriorBusinessDay($date, $workingDays, $holidays) | |
{ | |
$day = $this->getTradingDate($date, $workingDays, $holidays, false); | |
$this->debugMessage = sprintf( | |
'The business day before %s was %s', | |
$this->formatDate($date), | |
$this->formatDate($day, true) | |
); | |
$this->printDebugMessage(); | |
return $day; | |
} | |
private function formatDate($dates, $highlight = false) | |
{ | |
$ret = []; | |
if (is_array($dates)) { | |
array_walk( | |
$dates, | |
function ($date) use (&$ret, $highlight) { | |
$ret[] = $this->formatDate($date, $highlight); | |
} | |
); | |
} else { | |
// return sprintf("\033[40;1m%s\033[0m", (new \DateTime($dates))->format('D d M y')); | |
$format = $highlight ? "\033[30;47m%s\033[0m" : "%s"; | |
return sprintf($format, (new \DateTime($dates))->format('D, j M y')); | |
} | |
return $ret; | |
} | |
private function getBusinessDays($date, $workingDays, $holidays, $next, $numDays) | |
{ | |
$days = []; | |
$day = $date; | |
for ($i = 0; $i < $numDays; $i++) { | |
$day = $this->getTradingDate($day, $workingDays, $holidays, $next); | |
$days[] = $day; | |
} | |
return $days; | |
} | |
private function getTradingDate($date, $weekdays, $holidays, $next = true) | |
{ | |
$date = new \DateTime($date); | |
$IsAWeekday = function (\DateTime $date) use ($weekdays) { | |
return in_array($date->format('N'), $weekdays); | |
}; | |
$IsAHoliday = function (\DateTime $date) use ($holidays) { | |
return $holidays ? | |
in_array($date->format('Y-m-d'), $holidays) : false; | |
}; | |
do { | |
if ($next) { | |
$date->add(new \DateInterval('P1D')); | |
} else { | |
$date->sub(new \DateInterval('P1D')); | |
} | |
} while (!($IsAWeekday($date) && ! $IsAHoliday($date))); | |
return $date->format('Y-m-d'); | |
} | |
} | |
$calendar = new BusinessCalendar(true); | |
$weekdays = [1,2,3,4,5]; | |
$day = '2018-12-11'; | |
$nextDay = $calendar->getNextBusinessDay($day, $weekdays, []); | |
$nextDay = $calendar->getPriorBusinessDay($day, $weekdays, []); | |
$nextDay = $calendar->getNextBusinessDay($day, $weekdays, ['2018-08-06', '2018-08-07']); | |
$nextDays = $calendar->getNextBusinessDays($day, $weekdays, ['2018-08-06', '2018-08-07'], 2); | |
$nextDays = $calendar->getBusinessDaysForAPeriod( | |
$day, | |
'2018-12-18', | |
$weekdays, | |
['2018-12-12', '2018-12-15'] | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment