PHP ２つの日時の差の「時・分・秒」を取得する。タイムカードの打刻時刻など

## 概要

PHPの質問に、タイムカード打刻時刻datetimeから「時・分・秒」を求める方法の質問があったので、ぐぐったところ、差の秒数をgmdateに渡すサンプルやDateTime::diff()を使用するサンプルなどが出てきたが、どれも私はイマイチに感じたのでシンプルに書いた

## サンプル

出勤時刻 '2022-08-12 17:18:30'
休憩開始 '2022-08-12 23:30:00'
休憩終了 '2022-08-13 00:35:00'
退勤時刻 '2022-08-13 20:20:18'
※退勤時刻は計算の確認のため、
あえて24時間オーバーさせてます。

```test.php
<?php
/**
 * Class hmsClass
 */
class hmsClass {
    /**
     * @var int
     */
    public $h = 0;
    /**
     * @var int
     */
    public $m = 0;
    /**
     * @var int
     */
    public $s = 0;

    /**
     * 秒を「時、分、秒」へ
     *
     * @param int $time
     * @return false|static
     */
    public static function gethms($time) {

        // 数値でない時
        if (! preg_match('/^[\-+]?[0-9]+$/', strval($time))) {
            trigger_error(__METHOD__.'(): Argument #1 ($time) must be number', E_USER_WARNING);
            return false;
        }

        $time = intval($time);
        $obj = new static();
        $obj->h = (int)($time / 3600);
        $obj->m = ($time / 60) % 60;
        $obj->s = $time % 60;
        return $obj;
    }
}

// 打刻時刻 出勤時刻(1970年1月1日午前0時0分0秒からの経過秒)
$begin_time       = strtotime('2022-08-12 17:18:30');

// 打刻時刻 休憩開始時刻(1970年1月1日午前0時0分0秒からの経過秒)
$break_begin_time = strtotime('2022-08-12 23:30:00');

// 打刻時刻 休憩終了時刻(1970年1月1日午前0時0分0秒からの経過秒)
$break_end_time   = strtotime('2022-08-13 00:35:00');

// 打刻時刻 退勤時刻(1970年1月1日午前0時0分0秒からの経過秒)
$end_time         = strtotime('2022-08-13 20:20:18');


// 休憩時間(秒) = 休憩開始時刻(秒) - 休憩終了時刻(秒)
$break_time = $break_end_time - $break_begin_time;
$hms = hmsClass::gethms($break_time);
echo('$hms='.print_r($hms, true))."\n";
// $hms=stdClass hmsect
// (
//     [h] => 1
//     [m] => 5
//     [s] => 0
// )

// 労働時間(秒) = 退勤時刻(秒) - 出社時刻(秒) - 休憩時間(秒)
$work_time = $end_time - $begin_time - $break_time;
$hms = hmsClass::gethms($work_time);
echo('$hms='.print_r($hms, true))."\n";
// $hms=stdClass hmsect
// (
//     [h] => 25
//     [m] => 56
//     [s] => 48
// )
```

## テスト

コメントで負数の時のコメントをいただいたので、テストを書いてみました。

```gethmsTest.php
<?php
use PHPUnit\Framework\TestCase;

require 'gethms.php';

/**
 * Class gethmsTest
 */
class gethmsTest extends TestCase {

    public function test() {

        $hms = hmsClass::gethms(0);
        $this->assertSame(0, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(0, $hms->s);

        $hms = hmsClass::gethms(1);
        $this->assertSame(0, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(1, $hms->s);

        $hms = hmsClass::gethms(-1);
        $this->assertSame(0, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(-1, $hms->s);

        $hms = hmsClass::gethms(3600);
        $this->assertSame(1, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(0, $hms->s);

        $hms = hmsClass::gethms(-3600);
        $this->assertSame(-1, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(0, $hms->s);

        $hms = hmsClass::gethms(99999);
        $this->assertSame(27, $hms->h);
        $this->assertSame(46, $hms->m);
        $this->assertSame(39, $hms->s);

        $hms = hmsClass::gethms(-99999);
        $this->assertSame(-27, $hms->h);
        $this->assertSame(-46, $hms->m);
        $this->assertSame(-39, $hms->s);

        $hms = hmsClass::gethms('1');
        $this->assertSame(0, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(1, $hms->s);

        $hms = hmsClass::gethms('-1');
        $this->assertSame(0, $hms->h);
        $this->assertSame(0, $hms->m);
        $this->assertSame(-1, $hms->s);

        // 数字ではない時は例外
        $e = null;
        try {
            $hms = hmsClass::gethms('string');
        }
        catch (\Exception $e) {
            // trigger_errorメッセージの確認
            $this->assertSame('hmsClass::gethms(): Argument #1 ($time) must be number', $e->getMessage());
        }

        // 例外が発生した事を確認
        $this->assertIsObject($e);
    }
}
```