I have these datetime input in array from 8am until 5pm
2022-09-23 08:00:00
2022-09-23 08:30:00
2022-09-23 09:00:00
2022-09-23 09:30:00
2022-09-23 10:00:00
2022-09-23 10:30:00
2022-09-23 11:00:00
2022-09-23 13:00:00
2022-09-23 13:30:00
2022-09-23 14:00:00
2022-09-23 14:30:00
2022-09-23 15:00:00
2022-09-23 16:00:00
2022-09-23 16:30:00
2022-09-23 17:00:00
2022-09-23 17:30:00
My goal is to get/output previous array if input for datetime is greater than previous array and less than next array
Input datetime 2022-09-23 09:12:00, it will use 2022-09-23 09:00:00
Input datetime 2022-09-23 10:29:00, it will use 2022-09-23 10:00:00
My current code :
$final_datetime = array();
$datetime = "2022-09-22 09:12:00";
foreach ($arr as $k => $v) {
if ($v == $datetime) {
$final_datetime[] = $v;
} else {
$next1="";
$prev1="";
// Previous Array
if (isset($arr[$k-1])) {
$prev1 = $arr[$k-1];
}
// Next Array
if (isset($arr[$k 1])) {
$next1 = $arr[$k 1];
}
$prev2 = date_create($prev1);
$prev = date_format($prev2, 'Y-m-d H:i:s');
$next2 = date_create($next1);
$next = date_format($next2, 'Y-m-d H:i:s');
if ($datetime > $prev && $datetime < $next) {
echo 'Output : '.$prev.'<br/>';
} else {
}
}
}
My current output :
Output : 2022-09-22 08:30:00
Output : 2022-09-22 09:00:00
Expected Output :
Output : 2022-09-22 09:00:00
CodePudding user response:
Using date_format returns a string, but you want to compare DateTime objects for the given format 'Y-m-d H:i:s'
A few notes about the code.
- You are using
2022-09-23
in the array, but the variable$datetime = "2022-09-22 09:12:00";
is of the day before - It can be confusing to put in the comment
Previous Array
while you actually mean the previous array item - If you only want to return a single item, then you should either return the last item of the array
$final_datetime
or make$final_datetime
a string and overwrite the value everytime there is a new match. As you are using only a single value to check and the timeslots in sequence, you can just overwrite the value - At the end of the code when doing the comparison for the datetimes, you can first check the values of the variables that are in scope
Example code
$datetimeStr = "2022-09-23 09:12:00";
$final_datetime = "$datetimeStr is not within timeslots.";
$format = 'Y-m-d H:i:s';
$d = DateTime::createFromFormat($format, $datetimeStr);
foreach ($arr as $k => $v) {
if ($v === $datetimeStr) {
$final_datetime = $v;
break;
} else {
$prevDatetime = false;
$nextDateTime = false;
$prevStr = "";
$nextStr = "";
if (isset($arr[$k - 1])) {
$prevStr = $arr[$k - 1];
}
if (isset($arr[$k 1])) {
$nextStr = $arr[$k 1];
}
if ($prevStr) {
$prevDatetime = DateTime::createFromFormat($format, $prevStr);
}
if ($nextStr) {
$nextDateTime = DateTime::createFromFormat($format, $nextStr);
}
if ($prevDatetime && $nextDateTime && $d && ($d > $prevDatetime && $d < $nextDateTime)){
$final_datetime = $prevStr;
}
}
}
echo "Output: " . $final_datetime;
Result
Output: 2022-09-23 09:00:00
See a php demo.
CodePudding user response:
You were on the right track using date_create()
, the easiest way is to just add the input datetime to the array and convert everything into a DateTime
with array_map()
then pass it to sort()
. Then all you have to do is search the array for the input DateTime
. If it is the first or last item in the array that means its outside the range. Below, I wrote the process into a function that returns false
if the datetime falls outside the range (btw, your example searches for a datetime outside the range).
function findTimeSlotFor(string $dt_str, array $ts_arr)
{
if (in_array($dt_str, $ts_arr))
// return exact string match
return $dt_str;
// add it to the array
$ts_arr[] = $dt_str;
// convert to DateTimes
$dt_arr = array_map('date_create', $ts_arr);
$dt = date_create($dt_str);
// sort the array
sort($dt_arr);
// find where it landed
$landed_at_index = array_search($dt, $dt_arr);
if(0 == $landed_at_index || array_key_last($dt_arr) == $landed_at_index){
// input datetime outside the range of datetimes in the array
// adjust to your logic
return false;
}
// return the one before
return $dt_arr[$landed_at_index - 1]->format('Y-m-d H:i:s');
}
See the above code in action here: https://onlinephp.io/c/2cc7a