Delete timeslots from time range in php
I was trying to display free timeslots.
Given the data below, basically we need to find a way to display not booked timeslots during opening hours. Seems very easy to do as a human, but programming it...honestly I'm just going crazy :D
// open hours --------++++--++++----- [[08:00,12:00], [14:00,18:00]]
// booked slots ---------++----+------- [[09:00,11:00], [15:00,16:00]]
// expected --------+--+--+-++----- [[08,09], [11,12], [14,15], [16,18]]
Just for clarity I omitted minutes, which in real program will be present.
I have prepared a fiddle to start with: https://ideone.com/Z9pPi3
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','14:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
# - - - - - - - - helper functions
function timestring_to_time($hh_mm) {
return (int) strtotime("1970-01-01 $hh_mm");
}
function timestring_diff($hh_mm_start, $hh_mm_end) {
return abs(timestring_to_time($hh_mm_end) - timestring_to_time($hh_mm_start));
}
# find empty timeslots during opening hours given occupied slots
# H E R E G O E S T H E M A G I C
var_dump($valid_timeslots);
I tried to solve with if/else method but it's not working actually...there is a need of some kind recursion function.
php loops date datetime
|
show 2 more comments
I was trying to display free timeslots.
Given the data below, basically we need to find a way to display not booked timeslots during opening hours. Seems very easy to do as a human, but programming it...honestly I'm just going crazy :D
// open hours --------++++--++++----- [[08:00,12:00], [14:00,18:00]]
// booked slots ---------++----+------- [[09:00,11:00], [15:00,16:00]]
// expected --------+--+--+-++----- [[08,09], [11,12], [14,15], [16,18]]
Just for clarity I omitted minutes, which in real program will be present.
I have prepared a fiddle to start with: https://ideone.com/Z9pPi3
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','14:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
# - - - - - - - - helper functions
function timestring_to_time($hh_mm) {
return (int) strtotime("1970-01-01 $hh_mm");
}
function timestring_diff($hh_mm_start, $hh_mm_end) {
return abs(timestring_to_time($hh_mm_end) - timestring_to_time($hh_mm_start));
}
# find empty timeslots during opening hours given occupied slots
# H E R E G O E S T H E M A G I C
var_dump($valid_timeslots);
I tried to solve with if/else method but it's not working actually...there is a need of some kind recursion function.
php loops date datetime
Please paste all code into the question itself instead of off-site links. If that link changes/gets removed, the question will be useless for future visitors.
– Magnus Eriksson
Nov 16 '18 at 23:34
@MagnusEriksson done! Thanks for suggestion
– KeySee
Nov 16 '18 at 23:37
Have you actually tried anything? All I see is some arrays but no attempt at solving it? Also, are these values coming from a database?
– Magnus Eriksson
Nov 16 '18 at 23:39
Oh yeah, i created different monsters in order to solve this. None were good enought. The data are coming from plain text file. No database involved.
– KeySee
Nov 16 '18 at 23:42
@KeySee Btw,strtotime('1970-01-01')
will always return0
, since 1970-01-01 is epoch.
– Davіd
Nov 17 '18 at 0:16
|
show 2 more comments
I was trying to display free timeslots.
Given the data below, basically we need to find a way to display not booked timeslots during opening hours. Seems very easy to do as a human, but programming it...honestly I'm just going crazy :D
// open hours --------++++--++++----- [[08:00,12:00], [14:00,18:00]]
// booked slots ---------++----+------- [[09:00,11:00], [15:00,16:00]]
// expected --------+--+--+-++----- [[08,09], [11,12], [14,15], [16,18]]
Just for clarity I omitted minutes, which in real program will be present.
I have prepared a fiddle to start with: https://ideone.com/Z9pPi3
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','14:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
# - - - - - - - - helper functions
function timestring_to_time($hh_mm) {
return (int) strtotime("1970-01-01 $hh_mm");
}
function timestring_diff($hh_mm_start, $hh_mm_end) {
return abs(timestring_to_time($hh_mm_end) - timestring_to_time($hh_mm_start));
}
# find empty timeslots during opening hours given occupied slots
# H E R E G O E S T H E M A G I C
var_dump($valid_timeslots);
I tried to solve with if/else method but it's not working actually...there is a need of some kind recursion function.
php loops date datetime
I was trying to display free timeslots.
Given the data below, basically we need to find a way to display not booked timeslots during opening hours. Seems very easy to do as a human, but programming it...honestly I'm just going crazy :D
// open hours --------++++--++++----- [[08:00,12:00], [14:00,18:00]]
// booked slots ---------++----+------- [[09:00,11:00], [15:00,16:00]]
// expected --------+--+--+-++----- [[08,09], [11,12], [14,15], [16,18]]
Just for clarity I omitted minutes, which in real program will be present.
I have prepared a fiddle to start with: https://ideone.com/Z9pPi3
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','14:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
# - - - - - - - - helper functions
function timestring_to_time($hh_mm) {
return (int) strtotime("1970-01-01 $hh_mm");
}
function timestring_diff($hh_mm_start, $hh_mm_end) {
return abs(timestring_to_time($hh_mm_end) - timestring_to_time($hh_mm_start));
}
# find empty timeslots during opening hours given occupied slots
# H E R E G O E S T H E M A G I C
var_dump($valid_timeslots);
I tried to solve with if/else method but it's not working actually...there is a need of some kind recursion function.
php loops date datetime
php loops date datetime
edited Nov 17 '18 at 1:14
KeySee
asked Nov 16 '18 at 23:29
KeySeeKeySee
607717
607717
Please paste all code into the question itself instead of off-site links. If that link changes/gets removed, the question will be useless for future visitors.
– Magnus Eriksson
Nov 16 '18 at 23:34
@MagnusEriksson done! Thanks for suggestion
– KeySee
Nov 16 '18 at 23:37
Have you actually tried anything? All I see is some arrays but no attempt at solving it? Also, are these values coming from a database?
– Magnus Eriksson
Nov 16 '18 at 23:39
Oh yeah, i created different monsters in order to solve this. None were good enought. The data are coming from plain text file. No database involved.
– KeySee
Nov 16 '18 at 23:42
@KeySee Btw,strtotime('1970-01-01')
will always return0
, since 1970-01-01 is epoch.
– Davіd
Nov 17 '18 at 0:16
|
show 2 more comments
Please paste all code into the question itself instead of off-site links. If that link changes/gets removed, the question will be useless for future visitors.
– Magnus Eriksson
Nov 16 '18 at 23:34
@MagnusEriksson done! Thanks for suggestion
– KeySee
Nov 16 '18 at 23:37
Have you actually tried anything? All I see is some arrays but no attempt at solving it? Also, are these values coming from a database?
– Magnus Eriksson
Nov 16 '18 at 23:39
Oh yeah, i created different monsters in order to solve this. None were good enought. The data are coming from plain text file. No database involved.
– KeySee
Nov 16 '18 at 23:42
@KeySee Btw,strtotime('1970-01-01')
will always return0
, since 1970-01-01 is epoch.
– Davіd
Nov 17 '18 at 0:16
Please paste all code into the question itself instead of off-site links. If that link changes/gets removed, the question will be useless for future visitors.
– Magnus Eriksson
Nov 16 '18 at 23:34
Please paste all code into the question itself instead of off-site links. If that link changes/gets removed, the question will be useless for future visitors.
– Magnus Eriksson
Nov 16 '18 at 23:34
@MagnusEriksson done! Thanks for suggestion
– KeySee
Nov 16 '18 at 23:37
@MagnusEriksson done! Thanks for suggestion
– KeySee
Nov 16 '18 at 23:37
Have you actually tried anything? All I see is some arrays but no attempt at solving it? Also, are these values coming from a database?
– Magnus Eriksson
Nov 16 '18 at 23:39
Have you actually tried anything? All I see is some arrays but no attempt at solving it? Also, are these values coming from a database?
– Magnus Eriksson
Nov 16 '18 at 23:39
Oh yeah, i created different monsters in order to solve this. None were good enought. The data are coming from plain text file. No database involved.
– KeySee
Nov 16 '18 at 23:42
Oh yeah, i created different monsters in order to solve this. None were good enought. The data are coming from plain text file. No database involved.
– KeySee
Nov 16 '18 at 23:42
@KeySee Btw,
strtotime('1970-01-01')
will always return 0
, since 1970-01-01 is epoch.– Davіd
Nov 17 '18 at 0:16
@KeySee Btw,
strtotime('1970-01-01')
will always return 0
, since 1970-01-01 is epoch.– Davіd
Nov 17 '18 at 0:16
|
show 2 more comments
1 Answer
1
active
oldest
votes
Here is my solution - I assume that first hour in time-interval like ['08:00','12:00'] is always smaller than second hour. Instead of using your timestring_to_time
and timestring_diff
I write my own procedures to convert time to number - timeToNum
and numToTime
(you can easily extend them to include seconds: num=3600*hour + 60*min + sec
, sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)
):
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','11:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
#find empty timeslots during opening hours given occupied slots
function timeToNum($time) {
preg_match('/(dd):(dd)/', $time, $matches);
return 60*$matches[1] + $matches[2];
}
function numToTime($num) {
$m = $num%60;
$h = intval($num/60) ;
return ($h>9? $h:"0".$h).":".($m>9? $m:"0".$m);
}
// substraction interval $b=[b0,b1] from interval $a=[a0,a1]
function sub($a,$b)
{
// case A: $b inside $a
if($a[0]<=$b[0] and $a[1]>=$b[1]) return [ [$a[0],$b[0]], [$b[1],$a[1]] ];
// case B: $b is outside $a
if($b[1]<=$a[0] or $b[0]>=$a[1]) return [ [$a[0],$a[1]] ];
// case C: $a inside $b
if($b[0]<=$a[0] and $b[1]>=$a[1]) return [[0,0]]; // "empty interval"
// case D: left end of $b is outside $a
if($b[0]<=$a[0] and $b[1]<=$a[1]) return [[$b[1],$a[1]]];
// case E: right end of $b is outside $a
if($b[1]>=$a[1] and $b[0]>=$a[0]) return [[$a[0],$b[0]]];
}
// flat array and change numbers to time and remove empty (zero length) interwals e.g. [100,100]
// [[ [167,345] ], [ [433,644], [789,900] ]] to [ ["07:00","07:30"], ["08:00","08:30"], ["09:00","09:30"] ]
// (number values are not correct in this example)
function flatAndClean($interwals) {
$result = ;
foreach($interwals as $inter) {
foreach($inter as $i) {
if($i[0]!=$i[1]) {
//$result = $i;
$result = [numToTime($i[0]), numToTime($i[1])];
}
}
}
return $result;
}
// calculate new_opening_hours = old_opening_hours - occupied_slot
function cutOpeningHours($op_h, $occ_slot) {
foreach($op_h as $oh) {
$ohn = [timeToNum($oh[0]), timeToNum($oh[1])];
$osn = [timeToNum($occ_slot[0]), timeToNum($occ_slot[1])];
$subsn = sub($ohn, $osn);
}
return $subsn;
}
$oph = $opening_hours;
foreach($occupied_slots as $os) {
$oph = flatAndClean(cutOpeningHours($oph, $os ));
}
$valid_timeslots = $oph;
var_dump(json_encode(["result"=>$valid_timeslots]));
Working example HERE.
Algorithm
Calculate $new_opening_hours
from $old_opening_hours
by substract one occupied slot from it. And repeat that operation for every slot (each time getting new oppening hours array)
To make substraction of two interwals I :
- convert time like "08:30" to number
08*60+30 = 510
- Solve problem of substract two interwals [a0,a1]-[b0,b1] which can have 5 cases (look on
sub
function) - as example [500,800]-[600,700] = [ [500,600], [700,800]], - for each opening hours substract given occupied_slot and then clean and flat result to calc NEW openning hours
You can improve a little this solution by not conver time-number on each iteration but do it for each input data at the beginning and conver number-time for each output data at the end. And probably you can reduce number of conditions in sub
function - however current version is very clear.
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53346699%2fdelete-timeslots-from-time-range-in-php%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Here is my solution - I assume that first hour in time-interval like ['08:00','12:00'] is always smaller than second hour. Instead of using your timestring_to_time
and timestring_diff
I write my own procedures to convert time to number - timeToNum
and numToTime
(you can easily extend them to include seconds: num=3600*hour + 60*min + sec
, sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)
):
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','11:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
#find empty timeslots during opening hours given occupied slots
function timeToNum($time) {
preg_match('/(dd):(dd)/', $time, $matches);
return 60*$matches[1] + $matches[2];
}
function numToTime($num) {
$m = $num%60;
$h = intval($num/60) ;
return ($h>9? $h:"0".$h).":".($m>9? $m:"0".$m);
}
// substraction interval $b=[b0,b1] from interval $a=[a0,a1]
function sub($a,$b)
{
// case A: $b inside $a
if($a[0]<=$b[0] and $a[1]>=$b[1]) return [ [$a[0],$b[0]], [$b[1],$a[1]] ];
// case B: $b is outside $a
if($b[1]<=$a[0] or $b[0]>=$a[1]) return [ [$a[0],$a[1]] ];
// case C: $a inside $b
if($b[0]<=$a[0] and $b[1]>=$a[1]) return [[0,0]]; // "empty interval"
// case D: left end of $b is outside $a
if($b[0]<=$a[0] and $b[1]<=$a[1]) return [[$b[1],$a[1]]];
// case E: right end of $b is outside $a
if($b[1]>=$a[1] and $b[0]>=$a[0]) return [[$a[0],$b[0]]];
}
// flat array and change numbers to time and remove empty (zero length) interwals e.g. [100,100]
// [[ [167,345] ], [ [433,644], [789,900] ]] to [ ["07:00","07:30"], ["08:00","08:30"], ["09:00","09:30"] ]
// (number values are not correct in this example)
function flatAndClean($interwals) {
$result = ;
foreach($interwals as $inter) {
foreach($inter as $i) {
if($i[0]!=$i[1]) {
//$result = $i;
$result = [numToTime($i[0]), numToTime($i[1])];
}
}
}
return $result;
}
// calculate new_opening_hours = old_opening_hours - occupied_slot
function cutOpeningHours($op_h, $occ_slot) {
foreach($op_h as $oh) {
$ohn = [timeToNum($oh[0]), timeToNum($oh[1])];
$osn = [timeToNum($occ_slot[0]), timeToNum($occ_slot[1])];
$subsn = sub($ohn, $osn);
}
return $subsn;
}
$oph = $opening_hours;
foreach($occupied_slots as $os) {
$oph = flatAndClean(cutOpeningHours($oph, $os ));
}
$valid_timeslots = $oph;
var_dump(json_encode(["result"=>$valid_timeslots]));
Working example HERE.
Algorithm
Calculate $new_opening_hours
from $old_opening_hours
by substract one occupied slot from it. And repeat that operation for every slot (each time getting new oppening hours array)
To make substraction of two interwals I :
- convert time like "08:30" to number
08*60+30 = 510
- Solve problem of substract two interwals [a0,a1]-[b0,b1] which can have 5 cases (look on
sub
function) - as example [500,800]-[600,700] = [ [500,600], [700,800]], - for each opening hours substract given occupied_slot and then clean and flat result to calc NEW openning hours
You can improve a little this solution by not conver time-number on each iteration but do it for each input data at the beginning and conver number-time for each output data at the end. And probably you can reduce number of conditions in sub
function - however current version is very clear.
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
add a comment |
Here is my solution - I assume that first hour in time-interval like ['08:00','12:00'] is always smaller than second hour. Instead of using your timestring_to_time
and timestring_diff
I write my own procedures to convert time to number - timeToNum
and numToTime
(you can easily extend them to include seconds: num=3600*hour + 60*min + sec
, sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)
):
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','11:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
#find empty timeslots during opening hours given occupied slots
function timeToNum($time) {
preg_match('/(dd):(dd)/', $time, $matches);
return 60*$matches[1] + $matches[2];
}
function numToTime($num) {
$m = $num%60;
$h = intval($num/60) ;
return ($h>9? $h:"0".$h).":".($m>9? $m:"0".$m);
}
// substraction interval $b=[b0,b1] from interval $a=[a0,a1]
function sub($a,$b)
{
// case A: $b inside $a
if($a[0]<=$b[0] and $a[1]>=$b[1]) return [ [$a[0],$b[0]], [$b[1],$a[1]] ];
// case B: $b is outside $a
if($b[1]<=$a[0] or $b[0]>=$a[1]) return [ [$a[0],$a[1]] ];
// case C: $a inside $b
if($b[0]<=$a[0] and $b[1]>=$a[1]) return [[0,0]]; // "empty interval"
// case D: left end of $b is outside $a
if($b[0]<=$a[0] and $b[1]<=$a[1]) return [[$b[1],$a[1]]];
// case E: right end of $b is outside $a
if($b[1]>=$a[1] and $b[0]>=$a[0]) return [[$a[0],$b[0]]];
}
// flat array and change numbers to time and remove empty (zero length) interwals e.g. [100,100]
// [[ [167,345] ], [ [433,644], [789,900] ]] to [ ["07:00","07:30"], ["08:00","08:30"], ["09:00","09:30"] ]
// (number values are not correct in this example)
function flatAndClean($interwals) {
$result = ;
foreach($interwals as $inter) {
foreach($inter as $i) {
if($i[0]!=$i[1]) {
//$result = $i;
$result = [numToTime($i[0]), numToTime($i[1])];
}
}
}
return $result;
}
// calculate new_opening_hours = old_opening_hours - occupied_slot
function cutOpeningHours($op_h, $occ_slot) {
foreach($op_h as $oh) {
$ohn = [timeToNum($oh[0]), timeToNum($oh[1])];
$osn = [timeToNum($occ_slot[0]), timeToNum($occ_slot[1])];
$subsn = sub($ohn, $osn);
}
return $subsn;
}
$oph = $opening_hours;
foreach($occupied_slots as $os) {
$oph = flatAndClean(cutOpeningHours($oph, $os ));
}
$valid_timeslots = $oph;
var_dump(json_encode(["result"=>$valid_timeslots]));
Working example HERE.
Algorithm
Calculate $new_opening_hours
from $old_opening_hours
by substract one occupied slot from it. And repeat that operation for every slot (each time getting new oppening hours array)
To make substraction of two interwals I :
- convert time like "08:30" to number
08*60+30 = 510
- Solve problem of substract two interwals [a0,a1]-[b0,b1] which can have 5 cases (look on
sub
function) - as example [500,800]-[600,700] = [ [500,600], [700,800]], - for each opening hours substract given occupied_slot and then clean and flat result to calc NEW openning hours
You can improve a little this solution by not conver time-number on each iteration but do it for each input data at the beginning and conver number-time for each output data at the end. And probably you can reduce number of conditions in sub
function - however current version is very clear.
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
add a comment |
Here is my solution - I assume that first hour in time-interval like ['08:00','12:00'] is always smaller than second hour. Instead of using your timestring_to_time
and timestring_diff
I write my own procedures to convert time to number - timeToNum
and numToTime
(you can easily extend them to include seconds: num=3600*hour + 60*min + sec
, sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)
):
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','11:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
#find empty timeslots during opening hours given occupied slots
function timeToNum($time) {
preg_match('/(dd):(dd)/', $time, $matches);
return 60*$matches[1] + $matches[2];
}
function numToTime($num) {
$m = $num%60;
$h = intval($num/60) ;
return ($h>9? $h:"0".$h).":".($m>9? $m:"0".$m);
}
// substraction interval $b=[b0,b1] from interval $a=[a0,a1]
function sub($a,$b)
{
// case A: $b inside $a
if($a[0]<=$b[0] and $a[1]>=$b[1]) return [ [$a[0],$b[0]], [$b[1],$a[1]] ];
// case B: $b is outside $a
if($b[1]<=$a[0] or $b[0]>=$a[1]) return [ [$a[0],$a[1]] ];
// case C: $a inside $b
if($b[0]<=$a[0] and $b[1]>=$a[1]) return [[0,0]]; // "empty interval"
// case D: left end of $b is outside $a
if($b[0]<=$a[0] and $b[1]<=$a[1]) return [[$b[1],$a[1]]];
// case E: right end of $b is outside $a
if($b[1]>=$a[1] and $b[0]>=$a[0]) return [[$a[0],$b[0]]];
}
// flat array and change numbers to time and remove empty (zero length) interwals e.g. [100,100]
// [[ [167,345] ], [ [433,644], [789,900] ]] to [ ["07:00","07:30"], ["08:00","08:30"], ["09:00","09:30"] ]
// (number values are not correct in this example)
function flatAndClean($interwals) {
$result = ;
foreach($interwals as $inter) {
foreach($inter as $i) {
if($i[0]!=$i[1]) {
//$result = $i;
$result = [numToTime($i[0]), numToTime($i[1])];
}
}
}
return $result;
}
// calculate new_opening_hours = old_opening_hours - occupied_slot
function cutOpeningHours($op_h, $occ_slot) {
foreach($op_h as $oh) {
$ohn = [timeToNum($oh[0]), timeToNum($oh[1])];
$osn = [timeToNum($occ_slot[0]), timeToNum($occ_slot[1])];
$subsn = sub($ohn, $osn);
}
return $subsn;
}
$oph = $opening_hours;
foreach($occupied_slots as $os) {
$oph = flatAndClean(cutOpeningHours($oph, $os ));
}
$valid_timeslots = $oph;
var_dump(json_encode(["result"=>$valid_timeslots]));
Working example HERE.
Algorithm
Calculate $new_opening_hours
from $old_opening_hours
by substract one occupied slot from it. And repeat that operation for every slot (each time getting new oppening hours array)
To make substraction of two interwals I :
- convert time like "08:30" to number
08*60+30 = 510
- Solve problem of substract two interwals [a0,a1]-[b0,b1] which can have 5 cases (look on
sub
function) - as example [500,800]-[600,700] = [ [500,600], [700,800]], - for each opening hours substract given occupied_slot and then clean and flat result to calc NEW openning hours
You can improve a little this solution by not conver time-number on each iteration but do it for each input data at the beginning and conver number-time for each output data at the end. And probably you can reduce number of conditions in sub
function - however current version is very clear.
Here is my solution - I assume that first hour in time-interval like ['08:00','12:00'] is always smaller than second hour. Instead of using your timestring_to_time
and timestring_diff
I write my own procedures to convert time to number - timeToNum
and numToTime
(you can easily extend them to include seconds: num=3600*hour + 60*min + sec
, sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)
):
<?php
$opening_hours = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots = [['09:30','11:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = ;
#find empty timeslots during opening hours given occupied slots
function timeToNum($time) {
preg_match('/(dd):(dd)/', $time, $matches);
return 60*$matches[1] + $matches[2];
}
function numToTime($num) {
$m = $num%60;
$h = intval($num/60) ;
return ($h>9? $h:"0".$h).":".($m>9? $m:"0".$m);
}
// substraction interval $b=[b0,b1] from interval $a=[a0,a1]
function sub($a,$b)
{
// case A: $b inside $a
if($a[0]<=$b[0] and $a[1]>=$b[1]) return [ [$a[0],$b[0]], [$b[1],$a[1]] ];
// case B: $b is outside $a
if($b[1]<=$a[0] or $b[0]>=$a[1]) return [ [$a[0],$a[1]] ];
// case C: $a inside $b
if($b[0]<=$a[0] and $b[1]>=$a[1]) return [[0,0]]; // "empty interval"
// case D: left end of $b is outside $a
if($b[0]<=$a[0] and $b[1]<=$a[1]) return [[$b[1],$a[1]]];
// case E: right end of $b is outside $a
if($b[1]>=$a[1] and $b[0]>=$a[0]) return [[$a[0],$b[0]]];
}
// flat array and change numbers to time and remove empty (zero length) interwals e.g. [100,100]
// [[ [167,345] ], [ [433,644], [789,900] ]] to [ ["07:00","07:30"], ["08:00","08:30"], ["09:00","09:30"] ]
// (number values are not correct in this example)
function flatAndClean($interwals) {
$result = ;
foreach($interwals as $inter) {
foreach($inter as $i) {
if($i[0]!=$i[1]) {
//$result = $i;
$result = [numToTime($i[0]), numToTime($i[1])];
}
}
}
return $result;
}
// calculate new_opening_hours = old_opening_hours - occupied_slot
function cutOpeningHours($op_h, $occ_slot) {
foreach($op_h as $oh) {
$ohn = [timeToNum($oh[0]), timeToNum($oh[1])];
$osn = [timeToNum($occ_slot[0]), timeToNum($occ_slot[1])];
$subsn = sub($ohn, $osn);
}
return $subsn;
}
$oph = $opening_hours;
foreach($occupied_slots as $os) {
$oph = flatAndClean(cutOpeningHours($oph, $os ));
}
$valid_timeslots = $oph;
var_dump(json_encode(["result"=>$valid_timeslots]));
Working example HERE.
Algorithm
Calculate $new_opening_hours
from $old_opening_hours
by substract one occupied slot from it. And repeat that operation for every slot (each time getting new oppening hours array)
To make substraction of two interwals I :
- convert time like "08:30" to number
08*60+30 = 510
- Solve problem of substract two interwals [a0,a1]-[b0,b1] which can have 5 cases (look on
sub
function) - as example [500,800]-[600,700] = [ [500,600], [700,800]], - for each opening hours substract given occupied_slot and then clean and flat result to calc NEW openning hours
You can improve a little this solution by not conver time-number on each iteration but do it for each input data at the beginning and conver number-time for each output data at the end. And probably you can reduce number of conditions in sub
function - however current version is very clear.
edited Nov 18 '18 at 13:31
answered Nov 17 '18 at 11:57
Kamil KiełczewskiKamil Kiełczewski
9,51685893
9,51685893
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
add a comment |
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
Works great. Thanks Kamil !
– KeySee
Nov 17 '18 at 13:20
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53346699%2fdelete-timeslots-from-time-range-in-php%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Please paste all code into the question itself instead of off-site links. If that link changes/gets removed, the question will be useless for future visitors.
– Magnus Eriksson
Nov 16 '18 at 23:34
@MagnusEriksson done! Thanks for suggestion
– KeySee
Nov 16 '18 at 23:37
Have you actually tried anything? All I see is some arrays but no attempt at solving it? Also, are these values coming from a database?
– Magnus Eriksson
Nov 16 '18 at 23:39
Oh yeah, i created different monsters in order to solve this. None were good enought. The data are coming from plain text file. No database involved.
– KeySee
Nov 16 '18 at 23:42
@KeySee Btw,
strtotime('1970-01-01')
will always return0
, since 1970-01-01 is epoch.– Davіd
Nov 17 '18 at 0:16