I personally like working with higher level objects instead of just arrays or strings, so here's how I would tackle this. For some people, this is majorly overkill, and I totally get that, however the core method can easily be just rewritten as a global function, too, so hopefully that can be taken into account.
I think it is overall pretty straight-forward, and almost identical to your code except after exploding we convert to int
and then validate that the hours are in an expected range.
readonly class MySqlTime
{
public function __construct(
public int $hours,
public int $minutes,
public int $seconds,
) {
}
public static function fromMySqlTimeAsDurationInDay(string $time): self
{
[$hours, $minutes, $seconds] = array_map('intval', explode(':', $time));
// Ensure only positive values on a single day.
// MySql should already be throwing errors about minutes or seconds being out of range, so we don't
// need to check those.
// The seconds could include decimals, however for this purpose we are ignoring them.
if ($hours > 23 || $hours < 0) {
throw new InvalidArgumentException('Hours must be between 0 and 23');
}
return new self($hours, $minutes, $seconds);
}
public function toDateTime(DateTimeInterface $dateTime = null) : DateTimeInterface
{
$dateTime ??= new DateTimeImmutable();
return $dateTime->setTime($this->hours, $this->minutes, $this->seconds);
}
}
Usage:
var_dump(MySqlTime::fromMySqlTimeAsDurationInDay('12:34:56')->toDateTime());
Output:
object(DateTimeImmutable)#3 (3) {
["date"]=>
string(26) "2023-07-31 12:34:56.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
Demo: https://3v4l.org/B6mr4#v8.2.7