Created
January 9, 2026 21:53
-
-
Save haykuro/9a2aa90a24278009b684e6b7f8df4b9e to your computer and use it in GitHub Desktop.
BusinessDateTime, a class that allows you to do simple math for business days.
This file contains hidden or 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 BusinessDateTime extends DateTime | |
| { | |
| private $holidays = []; // Array to store holidays | |
| // Constructor | |
| public function __construct($time = "now", DateTimeZone $timezone = null) | |
| { | |
| parent::__construct($time, $timezone); | |
| $this->setDefaultHolidays(); // Preload default US holidays | |
| } | |
| /** | |
| * Modify the DateTime according to business day rules. | |
| * | |
| * @param string $modifier The modifier string (e.g., "+2 business days"). | |
| * @return DateTime|false | |
| */ | |
| public function modify(string $modifier): DateTime|false | |
| { | |
| if (preg_match('/^([\+\-]?\d+)\s*business days?$/i', $modifier, $matches)) { | |
| return $this->addBusinessDays((int)$matches[1]); | |
| } | |
| return parent::modify($modifier); | |
| } | |
| /** | |
| * Add business days to the current date. | |
| * | |
| * @param int $businessDays The number of business days to add (can be negative). | |
| * @return $this | |
| */ | |
| private function addBusinessDays(int $businessDays): self | |
| { | |
| $direction = $businessDays > 0 ? 1 : -1; | |
| $absDays = abs($businessDays); | |
| while ($absDays > 0) { | |
| $this->modify(($direction === 1 ? '+1 day' : '-1 day')); | |
| if ($this->isBusinessDay()) { | |
| $absDays--; | |
| } | |
| } | |
| return $this; | |
| } | |
| /** | |
| * Check if the current date is a business day. | |
| * | |
| * @return bool | |
| */ | |
| private function isBusinessDay(): bool | |
| { | |
| // Check if the current day is a weekend | |
| if (in_array($this->format('N'), [6, 7])) { | |
| return false; | |
| } | |
| // Check if the current date is a holiday | |
| if ($this->isHoliday()) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| /** | |
| * Check if the current date is a holiday. | |
| * | |
| * @return bool | |
| */ | |
| private function isHoliday(): bool | |
| { | |
| $year = (int)$this->format('Y'); | |
| $month = (int)$this->format('n'); | |
| $day = (int)$this->format('j'); | |
| // Define holidays using rules instead of fixed dates | |
| return $this->checkFixedHolidays($year, $month, $day) || | |
| $this->checkVariableHolidays($year, $month, $day); | |
| } | |
| /** | |
| * Define fixed holidays. | |
| */ | |
| private function checkFixedHolidays($year, $month, $day): bool | |
| { | |
| $fixedHolidays = [ | |
| '01-01', // New Year's Day | |
| '07-04', // Independence Day | |
| '11-11', // Veterans Day | |
| '12-25', // Christmas Day | |
| ]; | |
| return in_array(sprintf('%02d-%02d', $month, $day), $fixedHolidays); | |
| } | |
| /** | |
| * Define variable holidays. | |
| */ | |
| private function checkVariableHolidays($year, $month, $day): bool | |
| { | |
| // Variable holidays logic | |
| // Note: This is simplified and may require adjustments for holiday observances | |
| // Martin Luther King Jr. Day (Third Monday of January) | |
| if ($month === 1 && $day >= 15 && $this->format('N') == 1) { | |
| return true; | |
| } | |
| // Presidents' Day (Third Monday of February) | |
| if ($month === 2 && $day >= 15 && $this->format('N') == 1) { | |
| return true; | |
| } | |
| // Memorial Day (Last Monday of May) | |
| if ($month === 5 && $day > 24 && $this->format('N') == 1) { | |
| $lastMonday = (int)$this->format('j') - ((int)$this->format('j') % 7); | |
| return $lastMonday === 31; | |
| } | |
| // Labor Day (First Monday of September) | |
| if ($month === 9 && $day <= 7 && $this->format('N') == 1) { | |
| return true; | |
| } | |
| // Columbus Day (Second Monday of October) | |
| if ($month === 10 && $day >= 8 && $this->format('N') == 1) { | |
| return true; | |
| } | |
| // Thanksgiving Day (Fourth Thursday of November) | |
| if ($month === 11 && $day >= 22 && $this->format('N') == 4) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Set the holidays for the current object. | |
| * | |
| * @param array $holidays Array of holiday dates in 'Y-m-d' format. | |
| */ | |
| public function setHolidays(array $holidays): void | |
| { | |
| $this->holidays = $holidays; // This method isn't strictly necessary anymore | |
| } | |
| /** | |
| * Retrieve current holidays. | |
| * | |
| * @return array | |
| */ | |
| public function getHolidays(): array | |
| { | |
| return $this->holidays; // This method isn't strictly necessary anymore | |
| } | |
| /** | |
| * Set default holidays for the US. | |
| */ | |
| private function setDefaultHolidays(): void | |
| { | |
| // The default holidays will be handled in the isHoliday check | |
| } | |
| } |
This file contains hidden or 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 | |
| require_once __DIR__ . '/businessdatetime.php'; | |
| $businessDateTime = new BusinessDateTime(); | |
| echo $businessDateTime->format('Y-m-d'); // Current date | |
| $businessDateTime->modify('+12 business days'); | |
| echo $businessDateTime->format('Y-m-d'); // 12 business days later |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment