Skip to content

Instantly share code, notes, and snippets.

@d4rkne55
Last active July 16, 2020 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d4rkne55/73df627e377b445966de95bed184c3e4 to your computer and use it in GitHub Desktop.
Save d4rkne55/73df627e377b445966de95bed184c3e4 to your computer and use it in GitHub Desktop.
Class for working with time data/durations only
<?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