Skip to content

Instantly share code, notes, and snippets.

@kaho2063
Last active February 7, 2019 07:44
Show Gist options
  • Save kaho2063/f366582aba63b617fbe532eb385a10d2 to your computer and use it in GitHub Desktop.
Save kaho2063/f366582aba63b617fbe532eb385a10d2 to your computer and use it in GitHub Desktop.
時間範囲を引いた後の合計時間を出すための時間範囲クラス(php7.2.11でのみ動作確認)
<?php
/**
* 時間範囲型(PostgreSQLのtstzrange(https://www.postgresql.jp/document/9.4/html/rangetypes.html )を参考にした)
*/
class TimeRange {
/**
* 開始時刻
* @var \DateTimeImmutable null不許可
*/
private $start;
/**
* 終了時刻
* @var \DateTimeImmutable null不許可
*/
private $end;
/**
* 時間範囲型
* @param \DateTimeImmutable $start 開始時刻
* @param \DateTimeImmutable $end 終了時刻
* @throws \InvalidArgumentException 時刻のどちらかがnull、もしくは 開始時刻 < 終了時刻 でない場合に発生
*/
function __construct(\DateTimeImmutable $start, \DateTimeImmutable $end) {
if ($start === null || $end === null || $start >= $end) {
throw new \InvalidArgumentException();
}
$this->start = $start;
$this->end = $end;
}
/**
* 差分のTimeRange配列を返す
* 自身に引数が完全に含まれるときのみ2つのTimeRangeに分かれる
* @param TimeRange|TimeRange[] $rangeOrRangeArray 差分を求めたいTimeRangeかその配列
* @return TimeRange[] 差分のTimeRange配列
*/
function sub($rangeOrRangeArray): array {
$returnArray = [];
if ($rangeOrRangeArray instanceof TimeRange) {
if ($rangeOrRangeArray->start >= $this->end || $rangeOrRangeArray->end <= $this->start) {
// 自身と引数の期間が重複しないため、変更なし
$returnArray[] = clone $this;
} else {
if ($rangeOrRangeArray->start > $this->start) {
// 自身に引数の開始時刻が含まれる
$returnArray[] = new TimeRange($this->start, $rangeOrRangeArray->start);
}
if ($rangeOrRangeArray->end < $this->end) {
// 自身に引数の終了時刻が含まれる
$returnArray[] = new TimeRange($rangeOrRangeArray->end, $this->end);
}
}
return $returnArray;
}
if (!empty($rangeOrRangeArray) && (is_array($rangeOrRangeArray) || $rangeOrRangeArray instanceof \Traversable)) {
foreach ($rangeOrRangeArray as $value) {
if (!($value instanceof TimeRange)) {
throw new \InvalidArgumentException();
}
$returnArray += $this->sub($value);
}
return $returnArray;
}
throw new \InvalidArgumentException();
}
}
<?php
/**
* 時間範囲型用配列
*/
class TimeRangeArray extends \SplFixedArray {
/**
* 時間範囲型用配列
* @param TimeRangeArray|TimeRange[] $rangeArray 初期化時に追加するTimeRangeの配列
* @throws \InvalidArgumentException 引数が間違っていたとき発生する
*/
function __construct($rangeArray = null) {
parent::__construct();
if (!empty($rangeArray)) {
if (!(is_array($rangeArray) || $rangeArray instanceof \Traversable)) {
throw new \InvalidArgumentException();
}
foreach ($rangeArray as $value) {
if (!($value instanceof TimeRange)) {
throw new \InvalidArgumentException();
}
$this[] = $value;
}
}
}
/**
* 指定したインデックスに新しい値をセットする
* @param ?int $index インデックス
* @param TimeRange $newval 新しい値
* @throws \DomainException 重複する値を追加しようとしたときに発生
*/
public function offsetSet($index = null, $newval = null) {
if (!($newval instanceof TimeRange)) {
throw new \DomainException('Illegal value.');
}
if ($index === null) {
$index = count($this);
$this->setSize($index + 1);
}
// 重複する範囲は追加させない
foreach ($this as $range) {
if (($newval->start < $range->start && $newval->end > $range->start) || ($newval->start < $range->end && $newval->end > $range->end)) {
throw new \DomainException('Illegal value.');
}
}
return parent::offsetSet($index, $newval);
}
/**
* 差分のTimeRange配列を返す
* 自身に引数が完全に含まれるときのみ2つのTimeRangeに分かれる
* @param TimeRange[] $rangeArray 差分を求めたいTimeRangeの配列
* @return TimeRangeArray 差分のTimeRange配列
*/
function sub($rangeArray): TimeRangeArray {
if (!empty($rangeArray) && (is_array($rangeArray) || $rangeArray instanceof \Traversable)) {
$returnArray = new TimeRangeArray();
foreach ($this as $thisRange) {
$returnArray += $thisRange->sub($rangeArray);
}
return $returnArray;
}
throw new \InvalidArgumentException();
}
/**
* 時間範囲の合計時間を出す
* @return int 30分以上繰り上げ、それ未満切り捨ての時間範囲の合計時間(hours)
*/
function sum(): int {
$sumSeconds = 0;
foreach ($this as $range) {
$sumSeconds += ($range->end->getTimestamp() - $range->start->getTimestamp());
}
$sumMinutes = $sumSeconds / 60;
// 30分以上繰り上げ、それ未満切り捨て
$sumHours = round($sumMinutes / 60);
return $sumHours;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment