Last active
July 16, 2020 10:34
-
-
Save d4rkne55/73df627e377b445966de95bed184c3e4 to your computer and use it in GitHub Desktop.
Class for working with time data/durations only
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Time | |
{ | |
public $h; | |
public $i; | |
public $s; | |
public $f; | |
private static $unitData = array( | |
'h' => [], | |
'i' => [ | |
'max' => 60, | |
'parent' => 'h' | |
], | |
's' => [ | |
'max' => 60, | |
'parent' => 'i' | |
], | |
'f' => [ | |
'max' => 1000, | |
'parent' => 's' | |
] | |
); | |
public function __construct($timeStr) { | |
if ($timeStr === null || $timeStr === '') { | |
return; | |
} | |
$units = self::parseTime($timeStr); | |
foreach ($units as $unit => $value) { | |
$this->$unit = $value; | |
} | |
} | |
public static function createFromDateIntervalString($interval_spec) { | |
if (strpos($interval_spec, 'PT') !== 0) { | |
throw new LogicException('Only time portion allowed from the DateInterval specification!'); | |
} | |
$interval = new DateInterval($interval_spec); | |
$time = new self(null); | |
foreach (array_keys(self::$unitData) as $unit) { | |
$time->$unit = $interval->$unit; | |
} | |
return $time; | |
} | |
public function add($time) { | |
if (!is_object($time)) { | |
$time = new self($time); | |
} | |
foreach (array_keys(self::$unitData) as $unit) { | |
$this->$unit += $time->$unit; | |
} | |
} | |
public function sub($time) { | |
if (!is_object($time)) { | |
$time = new self($time); | |
} | |
foreach (array_keys(self::$unitData) as $unit) { | |
$this->$unit -= $time->$unit; | |
} | |
} | |
public function diff($time) { | |
$diff = new self(null); | |
foreach (array_keys(self::$unitData) as $unit) { | |
$diff->$unit = $time->$unit - $this->$unit; | |
} | |
$diff->recalculate(); | |
return $diff; | |
} | |
public function recalculate() { | |
foreach (array_reverse(self::$unitData) as $unit => $unitData) { | |
if (!isset($unitData['max'])) { | |
break; | |
} | |
if ($this->$unit >= $unitData['max'] || $this->$unit < 0) { | |
// floor() will practically round up for negative numbers, as needed | |
$this->{$unitData['parent']} += floor($this->$unit / $unitData['max']); | |
$this->$unit %= $unitData['max']; | |
// if remainder is negative, substract from full unit value | |
if ($this->$unit < 0) { | |
$this->$unit += $unitData['max']; | |
} | |
} | |
} | |
} | |
public function getSeconds() { | |
$units = ['s', 'i', 'h']; | |
$seconds = floor($this->f / 1000); | |
$ms = $this->f % 1000; | |
$seconds += $ms / 1000; | |
foreach ($units as $pos => $unit) { | |
$seconds += pow(60, $pos) * $this->$unit; | |
} | |
return $seconds; | |
} | |
public function format($format = null) { | |
$this->recalculate(); | |
$interval = new DateInterval("PT{$this->h}H{$this->i}M{$this->s}S"); | |
$interval->f = $this->f / 1000; | |
if ($format === null) { | |
$format = ''; | |
$units = array_keys(self::$unitData); | |
// first, biggest unit to show | |
$firstUnit = 's'; | |
foreach ($units as $unit) { | |
if ($this->$unit !== 0) { | |
$firstUnit = $unit; | |
break; | |
} | |
} | |
$firstUnitIdx = array_search($firstUnit, $units); | |
// units to show | |
$units = array_slice($units, $firstUnitIdx); | |
$specifier = []; | |
foreach ($units as $pos => $unit) { | |
$specifier[] = '%' . (($pos === 0) ? $unit : ucfirst($unit)); | |
} | |
$format = implode(':', $specifier); | |
} | |
return $interval->format($format); | |
} | |
private function parseTime($timeStr) { | |
$unitsR = array_reverse(explode(':', $timeStr)); | |
$time = array(); | |
$time['s'] = (int) $unitsR[0]; | |
$time['f'] = ($unitsR[0] - $time['s']) * 1000; | |
$time['i'] = (int) ($unitsR[1] ?? 0); | |
$time['h'] = (int) ($unitsR[2] ?? 0); | |
return $time; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment