Skip to content

Instantly share code, notes, and snippets.

@mikemadisonweb
Last active December 2, 2016 10:38
Show Gist options
  • Save mikemadisonweb/1e97c9026c0c9dcb8dac3547cdc31f49 to your computer and use it in GitHub Desktop.
Save mikemadisonweb/1e97c9026c0c9dcb8dac3547cdc31f49 to your computer and use it in GitHub Desktop.
Class DateIntervals - helper class to compute and format human readable date intervals , e.g. 1 hour 5 minutes 24 seconds
<?php
/**
* Helper class to compute human readable date intervals , e.g. 1 hour 5 minutes 24 seconds
*/
class DateIntervals
{
private $forms = [
'eng' => [
'years' => ['year', 'years'],
'months' => ['month', 'months'],
'days' => ['day', 'days'],
'hours' => ['hour', 'hours'],
'minutes' => ['minute', 'minutes'],
'seconds' => ['second', 'seconds'],
],
'rus' => [
'years' => ['год', 'года', 'лет'],
'months' => ['месяц', 'месяца', 'месяцев'],
'days' => ['день', 'дня', 'дней'],
'hours' => ['час', 'часа', 'часов'],
'minutes' => ['минута', 'минуты', 'минут'],
'seconds' => ['секунда', 'секунды', 'секунд'],
],
];
private $supported = ['eng' => true, 'rus' => true];
/**
* Get string interval
*
* @param string|\DateTime $date
* @param string $lang
* @param int $max Max number of units (e.g., 2 units is 6 month 1 week) starting from largest
* @param string $separator
*
* @return string
*
* @throws \Exception
*/
public function getInterval($date, $lang = 'eng', $max = 3, $separator = ' ')
{
if (!$date instanceof \DateTime) {
if (!is_string($date)) {
throw new \Exception('Expected formatted string of \DateTime object.');
}
$timestamp = $this->getTimestamp($date);
$date = new \DateTime();
$date->setTimestamp($timestamp);
}
return $this->getIntervalString($date, $lang, $max, $separator);
}
/**
* Plural forms of date strings
*
* @param $lang
* @param int $number Number of days, weeks or etc
* @param $wordForms
*
* @return string
*
* @throws \Exception
*/
private function pluralRules($lang, $number, $wordForms)
{
switch ($lang) {
case 'eng':
return $number.' '.(($number === 1) ? $wordForms[0] : $wordForms[1]);
case 'rus':
$cases = array(2, 0, 1, 1, 1, 2);
return $number.' '.$wordForms[($number % 100 > 4 && $number % 100 < 20) ? 2 : $cases[min($number % 10, 5)]];
default:
$supported = implode(', ', array_keys($this->supported));
throw new \Exception("Wrong language argument passed. Supported languages are ({$supported})");
}
}
/**
* Get string representation of Datetime object
*
* @param \DateTime $date
* @param string $lang
* @param int $max
* @param string $separator
*
* @return string
*
* @throws \Exception
*/
private function getIntervalString(\DateTime $date, $lang, $max, $separator)
{
$timeComponents = (array) $date->diff(new \DateTime());
$notNullTimeComponents = array_values(array_filter(array_slice($timeComponents, 0, 6)));
if (($max > 6) && ($max < 1) && !is_numeric($max)) {
throw new \Exception('Max number of units should be a number between 1 and 6.');
}
$interval = [];
for ($i = 0; $i < $max; ++$i) {
// Если diff вернёт 0 лет мы должны исключить ненужные элементы из списка форм
if (isset($notNullTimeComponents[$i])) {
$formForNotNullComponent = array_values(array_slice($this->forms[$lang], -count($notNullTimeComponents)));
$interval[] = $this->getFormattedTime($lang, $notNullTimeComponents[$i], $formForNotNullComponent[$i]);
}
}
return implode($separator, $interval);
}
/**
* Format date string
*
* @param string $lang
* @param $number
* @param $wordForms
*
* @return string
*/
private function getFormattedTime($lang, $number, $wordForms)
{
return $this->pluralRules($lang, $number, $wordForms);
}
/**
* @param $timestamp
*
* @return bool
*/
private function isValidTimeStamp($timestamp)
{
if (ctype_digit($timestamp) && strtotime(date('Y-m-d H:i:s', $timestamp)) === (int) $timestamp) {
return true;
} else {
return false;
}
}
/**
* @param $dateString
*
* @return int
*
* @throws \Exception
*/
private function getTimestamp($dateString)
{
if (!$this->isValidTimeStamp(strtotime($dateString))) {
throw new \Exception('Not valid date string.');
}
return strtotime($dateString);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment