Carbon Question really, making a only time stamp from a timestamp

Published 1 month ago by dan3460

I have an array of time slots for a specific day of the week. In the other hand i have a timestamp for a specific date and time. The time slots are formated as "08:00", "08:15", etc. i can easily make them into a carbon time using Carbon::createFromFormat(), no problem there. So in order to compare the timestamp with my time slots, seems to me that i have to get the timestamp, convert it to string, extract the time and convert that back to a carbon date to make the comparison. I looked in the Carbon docs but could not find either been able to compare only times or directly create a carbon date from the time part of the timestamp. I hope this is not too confusing

Best Answer (As Selected By dan3460)
Snapey

I built a test, not using Carbon to compare times. To me, this is far simpler

// setting up test data
$slots = collect(['08:00','08:15', '08:30', '09:00', '09:20', '09:40', '10:00', '10:30', '11:00', '12:00']);

$booking = \Carbon\Carbon::parse('2018-01-18 08:37');   // looking for 08:37


//number of minutes that we are trying to match 
$minutes = $booking->minute + $booking->hour*60;

$position = $slots->search(function($time) use ($minutes) {

    $times = explode(':',$time);
    return $times[0] * 60 + $times[1] > $minutes;

});

echo $slots[$position-1] . '-' . $slots[$position];  // 08:30 - 09:00

$minutes is set to the hours *60 plus the minutes

This is passed into a Laravel Collection search() function using a closure. This returns the first value that exceeds the minutes (ie the upper level of the time slot)

The result of the search is then used as an index on the slots so that the times can be pulled out. I demonstrate the correct match with an echo.

burlresearch

I'd say first: just convert everything to Carbon dates. This way everything is apples.

Then I'd loop through your timeslots and just convert them all to the same Y-m-d as your timestamp.

Then I'd loop through them to see if your timestamp was between them.

Actually, now that I type that, you can combine the last 2 steps into a single one.

Snapey
Snapey
1 month ago (842,895 XP)

or

forget the date. Convert all times to a number. eg go through the array and change 08:00 to (8 * 60+0) = 480 and 08:15 to (8 * 60+15) = 495

Then get the time element from the value to be tested, also convert it to minutes, and map over the array checking if the value is between two of the numbers.

It seems fiddly to start with but probably a whole lot quicker than juggling Carbon

dan3460

The array 0nly has slot times by "day" of the week. When converted to carbon will have a weird actual date but it can be compared with other times created in the same way. So I cannot change everything to carbon. Also changing the time to a number doesn't help with how to extract the time from the timestamp, still seems that I need a multi step process.

burlresearch

Can you post "the array" or party of it so we know what you are dealing with?

dan3460

It is a simple array with times as this:

slots={"08:00","08:15","08:30",....}

The timestamp, besides the actual date, can have a time such as 08:10:31. To make the comparison i could do something such as this:

$timePart=$timeStamp->toTimeString();
$compareTime=Carbon::createFromFormat('H:i:s',$timePart);

Then i can see on which slot the $timeStamp falls.

burlresearch

This is what I'm thinking:

    public function slots()
    {
        $ts      = Carbon::parse('-3 days');
        $slots   = ["08:00", "08:15", "08:30"];
        $matched = "24:00";
        foreach ($slots as $slot) {
            $cslot = Carbon::createFromFormat('H:i', $slot);
            $cslot->setDate($ts->year, $ts->month, $ts->day);
            if ($ts->lt($cslot)) {
                $matched = $slot;
                break;
            }
        }

        return $matched;
    }
dan3460

Thanks, that is very similar to what i have. The foreach slot part i doing it exactly the same way. The difference is that your $matched is coming from a timestamp from a database. I thought that may be a function that allows you to get just the time part but as a carbon instance to you can test against times, was looking a shorter way to do it. In other words, to create your matched value i will have to:

1- separate the timestamp into its components: $parts=explode(" ",$timestamp)
2 - create a carbon instance with the time part: $matched=Carbon::createFromFormat('H:i:s',$parts[1];

I was just wondering it it was a function that will do that directly from the database.

ejdelmonico

Have you tried using Carbon to convert both to timestamps for comparison? There is Carbon::createFromTimestamp and other similar methods.

dan3460

The problem there is that the array doesn't have a date, so it is created as a date from 1975 (or something like that), when you compare with the timestamp, the timestamp is always bigger.

burlresearch

This is why I used 'setDate' from the timestamp, $ts:

            $cslot = Carbon::createFromFormat('H:i', $slot);
            $cslot->setDate($ts->year, $ts->month, $ts->day);

This copies the Y-m-d to match the timestamp, but leaves the time-of-day as the $slot indicated.

Snapey
Snapey
1 month ago (842,895 XP)

I built a test, not using Carbon to compare times. To me, this is far simpler

// setting up test data
$slots = collect(['08:00','08:15', '08:30', '09:00', '09:20', '09:40', '10:00', '10:30', '11:00', '12:00']);

$booking = \Carbon\Carbon::parse('2018-01-18 08:37');   // looking for 08:37


//number of minutes that we are trying to match 
$minutes = $booking->minute + $booking->hour*60;

$position = $slots->search(function($time) use ($minutes) {

    $times = explode(':',$time);
    return $times[0] * 60 + $times[1] > $minutes;

});

echo $slots[$position-1] . '-' . $slots[$position];  // 08:30 - 09:00

$minutes is set to the hours *60 plus the minutes

This is passed into a Laravel Collection search() function using a closure. This returns the first value that exceeds the minutes (ie the upper level of the time slot)

The result of the search is then used as an index on the slots so that the times can be pulled out. I demonstrate the correct match with an echo.

dan3460

Hummmm... I think you are right. It does look simpler and probably quicker than calling carbon a bunch of times in a for loop.

Thanks to everyone for the ideas.

burlresearch

@dan3460 make sure to mark that approach 'best answer' then - if this solves your question.

Please sign in or create an account to participate in this conversation.