Last active
July 16, 2020 10:38
-
-
Save d4rkne55/9890a7fdcd0ab21dcae306d66fd062bf to your computer and use it in GitHub Desktop.
A DateInterval extension class
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 | |
/** | |
* This class brings support for milliseconds, explicit recalculation of carry-over points | |
* and human-friendly formatting | |
*/ | |
class DateIntervalEnhanced extends DateInterval | |
{ | |
public $ms = 0; | |
private $unitData = array( | |
'y' => [ | |
'fullUnit' => 'year(s)' | |
], | |
'm' => [ | |
'fullUnit' => 'month(s)' | |
], | |
'd' => [ | |
'fullUnit' => 'day(s)' | |
], | |
'h' => [ | |
'fullUnit' => 'hour(s)', | |
'max' => 24, | |
'parent' => 'd' | |
], | |
'i' => [ | |
'shortUnit' => 'm', | |
'fullUnit' => 'minute(s)', | |
'max' => 60, | |
'parent' => 'h' | |
], | |
's' => [ | |
'fullUnit' => 'second(s)', | |
'max' => 60, | |
'parent' => 'i' | |
], | |
'ms' => [ | |
'max' => 1000, | |
'parent' => 's' | |
] | |
); | |
public function __construct($interval_spec) { | |
if (preg_match('/\.(\d+)S$/', $interval_spec, $matches)) { | |
$this->ms = (int) str_pad($matches[1], 3, '0'); | |
$interval_spec = str_replace($matches[0], 'S', $interval_spec); | |
} | |
parent::__construct($interval_spec); | |
} | |
/** | |
* Recalculates carry-over points for time data (only) | |
*/ | |
public function recalculateTime() { | |
$vars = array_slice($this->unitData, 3); | |
foreach (array_reverse($vars) as $unit => $unitData) { | |
if ($this->$unit >= $unitData['max']) { | |
$this->{$unitData['parent']} += floor($this->$unit / $unitData['max']); | |
$this->$unit %= $unitData['max']; | |
} | |
} | |
} | |
/** | |
* Recalculates all carry-over points relative to a given date | |
* | |
* @param \DateTime|string $date | |
*/ | |
public function recalculateForDate($date) { | |
if (is_string($date)) { | |
$date = new DateTimeImmutable($date); | |
} | |
$dateAfter = $date->add($this); | |
$date = $date->diff($dateAfter); | |
$standardUnits = array_slice(array_keys($this->unitData), 0, -1); | |
foreach ($standardUnits as $unit) { | |
$this->$unit = $date->$unit; | |
} | |
} | |
/** | |
* This method formats the data in a human-friendly way | |
* | |
* @param int $maxUnits specifies the maximum units it should output, -1 for unlimited | |
* @param bool $fullUnits whether to display full unit names or abbreviations | |
* @return string | |
*/ | |
public function humanFormat($maxUnits = 2, $fullUnits = true) { | |
$units = array(); | |
foreach ($this->unitData as $unit => $unitData) { | |
if ($this->$unit > 0) { | |
$fullUnitName = isset($unitData['fullUnit']) ? $unitData['fullUnit'] : $unit; | |
$shortUnitName = isset($unitData['shortUnit']) ? $unitData['shortUnit'] : $unit; | |
if ($fullUnits) { | |
if ($this->$unit > 1) { | |
$unitName = preg_replace('/\((\w+)\)$/', '$1', $fullUnitName); | |
} else { | |
$unitName = preg_replace('/\(\w+\)$/', '', $fullUnitName); | |
} | |
} else { | |
$unitName = $shortUnitName; | |
} | |
$units[] = array( | |
$this->$unit, | |
$unitName | |
); | |
} | |
if ($maxUnits != -1 && count($units) >= $maxUnits) { | |
break; | |
} | |
} | |
$unitNameSeparator = ($fullUnits) ? ' ' : ''; | |
$str = ''; | |
foreach ($units as $i => $unit) { | |
if ($fullUnits) { | |
if ($i == count($units) - 1 && $i > 0) { | |
$str .= ' and '; | |
} elseif ($i > 0) { | |
$str .= ', '; | |
} | |
} else { | |
$str .= ' '; | |
} | |
$str .= implode($unitNameSeparator, $unit); | |
} | |
return trim($str); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment