3v4l.org

run code in 300+ PHP versions simultaneously
<?php if (!function_exists('easter_date')) { /** * @see https://github.com/steinger/easter-date/blob/master/easter.php * @return int unix timestamp of the day of easter */ function easter_date(int $year): int { $J = date('Y', mktime(0, 0, 0, 1, 1, $year)); $K = floor( $J/ 100 ); $M = 15 + floor(( 3*$K+3 ) / 4 ) - floor(( 8*$K+13 ) / 25 ); $S = 2 - floor(( 3*$K+3 ) / 4 ); $A = $J%19; $D = ( 19 * $A + $M) % 30; $R = floor( $D / 29 ) + ( floor( $D / 28 ) - floor( $D / 29 )) * floor( $A / 11 ); $OG = 21 + $D - $R; $SZ = 7 - ( ($J + floor( $J / 4 ) + $S ) % 7 ); $OE = 7 - ( ($OG - $SZ) % 7 ); $OS = $OG + $OE; return mktime(0,0,0,3,$OS,$J); } } //observed closures $closures = [ '2017' => [ '2017-08-28', '2017-08-29', '2017-08-30', '2017-08-31', '2017-09-01' ] ]; file_put_contents(Holiday::CLOSURES_FILE, '<?php return ' . var_export($closures, true) . ';'); class Holiday { public const CLOSURES_FILE = '/tmp/closures.php'; private static $closuresLoaded = false; /** * date format = N (1 = Monday, ...) * @var array */ private static $workingDays = [1, 2, 3, 4, 5]; private static $observableHolidays = []; /** * Is submitted date a holiday? * * @param DateTime $date * @return bool */ public static function isHoliday(\DateTimeInterface $date): bool { $holidays = self::getHolidays($date); return \array_key_exists($date->format('Y-m-d'), \array_flip($holidays[$date->format('Y')])); } public static function isWorkDay(\DateTimeInterface $date): bool { if (!\in_array($date->format('N'), self::$workingDays)) { return false; } if (self::isHoliday($date)) { return false; } return true; } /** * Count number of weekdays within a given date span, excluding holidays * * @param \DateTimeInterface $from * @param \DateTimeInterface $to * @return int * @throws Exception */ public static function countWeekDays(\DateTimeInterface $from, \DateTimeInterface $to = null) { if (is_null($to)) { return null; } // from stackoverflow: // http://stackoverflow.com/questions/336127/calculate-business-days#19221403 $from = clone $from; $from->setTime(0, 0, 0); $to = clone $to; $to->setTime(0, 0, 0); $interval = new DateInterval('P1D'); $to->add($interval); $period = new DatePeriod($from, $interval, $to); $days = 0; /** @var DateTime $date */ foreach ($period as $date) { if (self::isWorkDay($date)) { $days++; } } return $days; } /** * Return count of weekdays in given month * * @param int $month * @param int $year * @return int * @throws Exception */ public static function countWeekDaysInMonthToDate(int $month, int $year): int { $today = new \DateTimeImmutable(); $d1 = $today->setDate($year, $month, 1); $d2 = $d1->modify('last day of this month'); return self::countWeekDays($d1, min($d2, $today)); } /** * @see https://www.php.net/manual/en/function.easter-date.php * @param \DateTimeInterface $date * @return \DateTimeImmutable */ private static function getEaster(\DateTimeInterface $date): \DateTimeImmutable { return (new \DateTimeImmutable())->setTimestamp(\easter_date($date->format('Y'))); } /** * Returns an array of strings representing holidays in format 'Y-m-d' * * @return array|string[][] */ public static function getHolidays(\DateTimeInterface $start): array { static $relativeHolidays = [ 'new years day' => 'first day of January', 'easter' => [__CLASS__, 'getEaster'], 'memorial day' => 'second Monday of May', 'independence day' => 'July 4th', 'labor day' => 'first Monday of September', 'thanksgiving' => 'fourth Thursday of November', 'black friday' => 'fourth Thursday of November + 1 day', 'christmas' => 'December 25th', 'new years eve' => 'last day of December', //... add others like Veterans Day, MLK, Columbus Day, etc ]; if (!$start instanceof \DateTimeImmutable) { //force using DateTimeImmutable $start = \DateTimeImmutable::createFromMutable($start); } //build the holidays to the specified year $start = $start->modify('first day of this year'); //always generate an entire years worth of holidays $period = new \DatePeriod($start, new \DateInterval('P1Y'), 0); foreach ($period as $date) { $year = $date->format('Y'); if (array_key_exists($year, self::$observableHolidays)) { continue; } self::$observableHolidays[$year] = []; foreach ($relativeHolidays as $relativeHoliday) { if (\is_callable($relativeHoliday)) { $holidayDate = $relativeHoliday($date); } elseif (0 === \strpos($relativeHoliday, 'P')) { $holidayDate = $date->add(new \DateInterval($relativeHoliday)); } else { $holidayDate = $date->modify($relativeHoliday); } self::$observableHolidays[$year][] = $holidayDate->format('Y-m-d'); } } //optionally do not use include file //return self::$observableHolidays; $holidays = self::$observableHolidays; if (\is_file(self::CLOSURES_FILE)) { foreach (include self::CLOSURES_FILE as $year => $dates) { if (!\array_key_exists($year, $holidays)) { $holidays[$year] = []; } $holidays[$year] = \array_merge($holidays[$year], $dates); } } return $holidays; } } $date = new \DateTime('2017-08-28'); $holidays = Holiday::getHolidays($date); var_export($holidays); echo \PHP_EOL; var_dump(Holiday::isHoliday($date));
Output for git.master_jit, git.master
Fatal error: Uncaught Exception: DatePeriod::__construct(): Recurrence count must be greater than 0 in /in/fnj67:171 Stack trace: #0 /in/fnj67(171): DatePeriod->__construct(Object(DateTimeImmutable), Object(DateInterval), 0) #1 /in/fnj67(207): Holiday::getHolidays(Object(DateTimeImmutable)) #2 {main} thrown in /in/fnj67 on line 171
Process exited with code 255.
Output for rfc.property-hooks
Fatal error: Uncaught DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater than 0 in /in/fnj67:171 Stack trace: #0 /in/fnj67(171): DatePeriod->__construct(Object(DateTimeImmutable), Object(DateInterval), 0) #1 /in/fnj67(207): Holiday::getHolidays(Object(DateTimeImmutable)) #2 {main} thrown in /in/fnj67 on line 171
Process exited with code 255.

This tab shows result from various feature-branches currently under review by the php developers. Contact me to have additional branches featured.

Active branches

Archived branches

Once feature-branches are merged or declined, they are no longer available. Their functionality (when merged) can be viewed from the main output page


preferences:
75.29 ms | 407 KiB | 5 Q