P粉5305192342023-08-01 09:41:04
I personally prefer to use high-level objects instead of just arrays or strings, so this is how I approach it. This may be overkill for some, which I totally understand, but the core methods can also be easily rewritten as global functions, so hopefully this can be taken into account.
I think overall it's very simple and straightforward, almost identical to your code, except after splitting we convert it to an integer and then verify that the hour is within the 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