3v4l.org

run code in 300+ PHP versions simultaneously
<?php $dates[] = array("date" => "2016-02-18 02:00:00", "duration" => "600"); // 10 mins $dates[] = array("date" => "2016-02-18 02:05:00", "duration" => "300"); // 5 mins $dates[] = array("date" => "2016-02-18 02:10:00", "duration" => "600"); $dates[] = array("date" => "2016-02-18 02:15:00", "duration" => "300"); $dates[] = array("date" => "2016-02-18 02:20:00", "duration" => "600"); $dates[] = array("date" => "2016-02-18 02:25:00", "duration" => "300"); $dates[] = array("date" => "2016-02-18 02:30:00", "duration" => "600"); $alreadyChosenDates[] = array("date" => "2016-02-18 02:10:00", "duration" => "600"); class ScheduleList { /** * A list of all the dates that: * 1) After the 'chosen' start date * 2) Do not overlap with any 'chosen' date * * @var array $candidates */ private $candidates = array(); /** * Any date record we didn't use. * * @var array $unused */ private $unused = array(); /** * List of dates that must be included in the 'final' list. * The earliest date is assumed to be a start date and everything must be later. * * @var array $chosen */ private $chosen = array(); /** * Ordered list of `none overlapping' dates from the chosen and candidates * * @var array $final */ private $final = array(); /** * These are the date lists. * They will be converted, sorted and filters as required. * * @param array $chosenDates * @param array $candidateDates * @return void */ public function __construct(array $chosenDates, array $candidateDates) { // convert and sort foreach ($chosenDates as $when) { $this->chosen[] = $this->makeDateRange($when); } if (count($this->chosen) > 1) { // sort them so we can easily compare against them usort($this->chosen, function ($when1, $when2) { return $when1['startTime'] - $when2['startTime']; }); } // add chosen to the final list $this->final = $this->chosen; // convert, sort and filter the candidates $this->convertCandidates($candidateDates); } /** * Add the candidates to the final list * * Known conditions: * o Both lists are in start date order * o No candidates overlap with any chosen date * o The candidates may overlap with each other - Hmm... need to check... * * Note: The '$this->isOverlapsAny' method - as it is used a lot will be expensive (O(n^2)) * I can think of ways to reduce that - will happen when it is refactored ;-/ * * @return array */ public function generateList() { // first candidate MUST be the closest to the first chosen date due to sorting. $this->final[] = array_shift($this->candidates); // move it to the final list // Add the remaining candidates checking for overlaps as we do so... foreach ($this->candidates as $candidate) { if ($this->isOverlapAny($candidate, $this->final)) { $this->unused[] = $candidate; } else { $this->final[] = $candidate; } } // sort final by start times - makes it easy to reason about usort($this->final, function ($when1, $when2) { return $when1['startTime'] - $when2['startTime']; }); return $this->final; } /* * Convert each date to a dateRange that is easier to check and display * * o Check each candidate date for ovelapping with any of the 'chosen dates' * o Check if before first chosen start data. */ protected function convertCandidates(array $candidateDates) { foreach ($candidateDates as $idx => $when) { $candidate = $this->makeDateRange($when); // overlaps with any chosen then ignore it if ($this->isOverlapAny($candidate, $this->chosen)) { // ignore it $this->unused[] = $candidate; // record failed ones so easy to check continue; } // ignore if before first chosen start time if ($candidate['endTime'] <= $this->chosen[0]['startTime']) { $this->unused[] = $candidate; // record failed ones so easy to check continue; } $this->candidates[] = $candidate; } // sort candidates by start times - makes it easy to reason about usort($this->candidates, function ($when1, $when2) { return $when1['startTime'] - $when2['startTime']; }); } /** * Convert to UNIX timestamp as seconds will make the calculations easier * * The result has: * 1) the time as a date object - I can do calculations / format it whatever * 2) startTime as epoch seconds * 3) endTime as epoch seconds * * @param array $when * * @return array */ public function makeDateRange(array $when) { $dt = \DateTime::createFromFormat('Y-m-d H:i:s', $when['date']); $result = array(); $result['when'] = $dt; $result['duration'] = (int) $when['duration']; $result['startTime'] = (int) $dt->format('U'); $result['endTime'] = (int) $result['startTime'] + $when['duration']; return $result; } /** * if start is after other end OR end is before other start then they don't overlap * * Easiest way is to check that they don't overlap and reverse the result */ public function isOverlap($when1, $when2) { return ! ( $when1['endTime'] <= $when2['startTime'] || $when1['startTime'] >= $when2['endTime']); } /** * Check if candidate overlaps any of the dates in the list * * @param array $candidate * @param array $whenList -- list of non-overlapping dates * * @return boolean true if overlaps */ function isOverlapAny($candidate, $whenList) { foreach ($whenList as $when) { if ($this->isOverlap($when, $candidate)) { // ignore it return true; } } return false; } /** * Show a date formatted for debugging purposes * * @param array $when * @return void */ public function displayWhen(array $when) { echo PHP_EOL, 'date: ', $when['when']->format('Y-m-d H:i:s'), ' len: ', $when['duration'], ' end: ', date('Y-m-d H:i:s', $when['endTime']), ' start: ', $when['startTime'], ' end: ', $when['endTime']; } /* * `Getters` so you can see what happened */ public function getChosen() { return $this->chosen; } public function getUnused() { return $this->unused; } public function getCandidates() { return $this->candidates; } public function getFinal() { return $this->final; } /** * properties - for those of us that like them */ public function __get($name) { if (property_exists($this, $name)) { return $this->$name; } return null; } } $datesListGenerator = new ScheduleList($alreadyChosenDates, $dates); $final = $datesListGenerator->generateList(); foreach ($datesListGenerator->getUnused() as $when) { $datesListGenerator->displayWhen($when); }

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).

VersionSystem time (s)User time (s)Memory (MiB)
8.3.60.0110.00717.00
8.3.50.0130.00718.07
8.3.40.0040.01119.07
8.3.30.0130.00318.90
8.3.20.0040.00419.02
8.3.10.0080.00021.95
8.3.00.0040.00419.50
8.2.180.0090.00916.47
8.2.170.0070.01122.96
8.2.160.0110.00420.52
8.2.150.0050.00324.18
8.2.140.0040.00424.66
8.2.130.0110.00326.16
8.2.120.0060.00318.96
8.2.110.0160.00320.64
8.2.100.0090.00318.28
8.2.90.0050.00317.94
8.2.80.0000.00820.52
8.2.70.0090.00018.15
8.2.60.0000.00818.16
8.2.50.0000.00918.34
8.2.40.0030.00620.39
8.2.30.0030.00619.49
8.2.20.0030.00518.14
8.2.10.0040.00418.26
8.2.00.0050.00317.95
8.1.280.0140.00725.92
8.1.270.0050.00322.23
8.1.260.0050.00326.35
8.1.250.0000.00828.09
8.1.240.0100.00623.88
8.1.230.0090.00320.99
8.1.220.0050.00318.04
8.1.210.0000.00818.90
8.1.200.0040.00417.60
8.1.190.0000.01017.48
8.1.180.0050.00318.10
8.1.170.0050.00318.72
8.1.160.0060.00320.67
8.1.150.0030.00622.09
8.1.140.0000.00819.77
8.1.130.0040.00417.85
8.1.120.0030.00717.57
8.1.110.0000.00817.55
8.1.100.0060.00617.65
8.1.90.0040.00417.55
8.1.80.0040.00417.65
8.1.70.0040.00417.66
8.1.60.0000.00817.71
8.1.50.0060.00317.64
8.1.40.0050.00317.66
8.1.30.0040.00417.81
8.1.20.0030.00517.86
8.1.10.0040.00417.65
8.1.00.0000.00817.76
8.0.300.0070.00020.23
8.0.290.0060.00316.88
8.0.280.0030.00318.62
8.0.270.0040.00417.41
8.0.260.0050.00217.34
8.0.250.0070.00017.29
8.0.240.0070.00017.28
8.0.230.0040.00417.16
8.0.220.0020.00517.20
8.0.210.0040.00417.25
8.0.200.0000.00617.12
8.0.190.0040.00417.17
8.0.180.0040.00717.23
8.0.170.0040.00417.07
8.0.160.0000.00717.18
8.0.150.0050.00317.17
8.0.140.0050.00217.19
8.0.130.0030.00313.62
8.0.120.0000.00817.20
8.0.110.0030.00517.15
8.0.100.0040.00417.13
8.0.90.0000.00817.22
8.0.80.0030.01217.14
8.0.70.0060.00317.28
8.0.60.0000.00817.20
8.0.50.0050.00317.20
8.0.30.0100.01017.31
8.0.20.0100.01117.40
8.0.10.0000.00717.46
8.0.00.0130.00617.11
7.4.330.0050.00015.55
7.4.320.0060.00016.74
7.4.300.0000.00716.66
7.4.290.0000.00716.72
7.4.280.0040.00416.75
7.4.270.0030.00316.72
7.4.260.0040.00416.64
7.4.250.0000.00816.55
7.4.240.0000.00716.76
7.4.230.0030.00316.46
7.4.220.0070.01116.73
7.4.210.0110.00716.69
7.4.200.0060.00316.69
7.4.160.0090.00816.71
7.4.150.0150.00317.40
7.4.140.0130.00617.86
7.4.130.0080.01316.78
7.4.120.0080.01316.69
7.4.110.0190.00716.79
7.4.100.0150.00416.80
7.4.90.0090.00916.72
7.4.80.0130.01019.39
7.4.70.0110.00516.56
7.4.60.0140.00316.82
7.4.50.0030.01116.74
7.4.40.0150.01116.63
7.4.30.0040.01516.78
7.4.00.0030.01215.26
7.3.330.0000.00513.50
7.3.320.0060.00013.37
7.3.310.0000.00816.67
7.3.300.0000.00716.42
7.3.290.0050.00216.51
7.3.280.0120.00816.48
7.3.270.0070.01417.40
7.3.260.0100.00816.65
7.3.250.0110.00716.71
7.3.240.0130.00816.75
7.3.230.0090.00916.71
7.3.210.0150.00316.45
7.3.200.0110.00716.68
7.3.190.0120.01216.67
7.3.180.0090.00816.55
7.3.170.0120.00616.70
7.3.160.0060.01116.73
7.2.330.0130.00616.82
7.2.320.0160.00316.59
7.2.310.0070.01117.11
7.2.300.0130.01316.77
7.2.290.0100.01017.06
7.2.60.0040.00917.17
7.2.50.0030.01016.92
7.2.00.0000.01619.35
7.1.200.0110.00415.88
7.1.70.0050.00217.14
7.1.60.0090.00617.41
7.1.00.0000.08022.36
7.0.200.0070.00715.20
7.0.130.0170.05322.03
7.0.120.0130.05022.04
7.0.110.0070.06022.07
7.0.100.0000.06022.13
7.0.90.0070.05721.99
7.0.80.0030.06022.12
7.0.70.0100.05321.98
7.0.60.0100.05321.97
7.0.50.0100.06022.16
7.0.40.0100.06022.11
7.0.30.0070.05721.98
7.0.20.0100.05722.05
7.0.10.0030.06322.07
7.0.00.0130.05321.98
5.6.280.0070.05721.13
5.6.270.0000.06721.09
5.6.260.0130.05321.13
5.6.250.0070.05721.13
5.6.240.0000.06720.98
5.6.230.0030.06020.83
5.6.220.0070.05721.02
5.6.210.0200.04720.99
5.6.200.0130.05321.07
5.6.190.0130.08021.08
5.6.180.0000.06021.08
5.6.170.0070.05720.95
5.6.160.0030.06721.11
5.6.150.0100.06021.05
5.6.140.0070.06721.13
5.6.130.0100.05721.13
5.6.120.0100.06720.90
5.6.110.0130.05721.04
5.6.100.0100.07720.88
5.6.90.0100.05720.77
5.6.80.0070.05320.18
5.6.70.0100.05020.36
5.6.60.0170.05320.21
5.6.50.0070.05320.28
5.6.40.0030.07020.34
5.6.30.0070.06020.33
5.6.20.0070.06020.32
5.6.10.0030.06020.42
5.6.00.0100.07020.26

preferences:
63.51 ms | 401 KiB | 5 Q