Skip to content

Commit

Permalink
Extract RelativeTimeFormatter from Time & Date.
Browse files Browse the repository at this point in the history
Pulling these methods out into a separate object will let code be shared
with the immutable variants that are being added. It also allows for
code to be shared between date and time objects.
  • Loading branch information
markstory committed Nov 23, 2015
1 parent 1428216 commit 1c6ac85
Show file tree
Hide file tree
Showing 4 changed files with 411 additions and 368 deletions.
161 changes: 1 addition & 160 deletions src/I18n/Date.php
Expand Up @@ -130,165 +130,6 @@ class Date extends MutableDate implements JsonSerializable
*/
public function timeAgoInWords(array $options = [])
{
$date = $this;

$options += [
'from' => static::now(),
'timezone' => null,
'format' => static::$wordFormat,
'accuracy' => static::$wordAccuracy,
'end' => static::$wordEnd,
'relativeString' => __d('cake', '%s ago'),
'absoluteString' => __d('cake', 'on %s'),
];
if (is_string($options['accuracy'])) {
foreach (static::$wordAccuracy as $key => $level) {
$options[$key] = $options['accuracy'];
}
} else {
$options['accuracy'] += static::$wordAccuracy;
}
if ($options['timezone']) {
$date = $date->timezone($options['timezone']);
}

$now = $options['from']->format('U');
$inSeconds = $date->format('U');
$backwards = ($inSeconds > $now);

$futureTime = $now;
$pastTime = $inSeconds;
if ($backwards) {
$futureTime = $inSeconds;
$pastTime = $now;
}
$diff = $futureTime - $pastTime;

if (!$diff) {
return __d('cake', 'today');
}

if ($diff > abs($now - (new static($options['end']))->format('U'))) {
return sprintf($options['absoluteString'], $date->i18nFormat($options['format']));
}

// If more than a week, then take into account the length of months
if ($diff >= 604800) {
list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $futureTime));

list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $pastTime));
$weeks = $days = $hours = $minutes = $seconds = 0;

$years = $future['Y'] - $past['Y'];
$months = $future['m'] + ((12 * $years) - $past['m']);

if ($months >= 12) {
$years = floor($months / 12);
$months = $months - ($years * 12);
}
if ($future['m'] < $past['m'] && $future['Y'] - $past['Y'] === 1) {
$years--;
}

if ($future['d'] >= $past['d']) {
$days = $future['d'] - $past['d'];
} else {
$daysInPastMonth = date('t', $pastTime);
$daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y']));

if (!$backwards) {
$days = ($daysInPastMonth - $past['d']) + $future['d'];
} else {
$days = ($daysInFutureMonth - $past['d']) + $future['d'];
}

if ($future['m'] != $past['m']) {
$months--;
}
}

if (!$months && $years >= 1 && $diff < ($years * 31536000)) {
$months = 11;
$years--;
}

if ($months >= 12) {
$years = $years + 1;
$months = $months - 12;
}

if ($days >= 7) {
$weeks = floor($days / 7);
$days = $days - ($weeks * 7);
}
} else {
$years = $months = $weeks = 0;
$days = floor($diff / 86400);

$diff = $diff - ($days * 86400);

$hours = floor($diff / 3600);
$diff = $diff - ($hours * 3600);

$minutes = floor($diff / 60);
$diff = $diff - ($minutes * 60);
$seconds = $diff;
}

$fWord = $options['accuracy']['day'];
if ($years > 0) {
$fWord = $options['accuracy']['year'];
} elseif (abs($months) > 0) {
$fWord = $options['accuracy']['month'];
} elseif (abs($weeks) > 0) {
$fWord = $options['accuracy']['week'];
} elseif (abs($days) > 0) {
$fWord = $options['accuracy']['day'];
}

$fNum = str_replace(['year', 'month', 'week', 'day'], [1, 2, 3, 4], $fWord);

$relativeDate = '';
if ($fNum >= 1 && $years > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '{0} year', '{0} years', $years, $years);
}
if ($fNum >= 2 && $months > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '{0} month', '{0} months', $months, $months);
}
if ($fNum >= 3 && $weeks > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '{0} week', '{0} weeks', $weeks, $weeks);
}
if ($fNum >= 4 && $days > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '{0} day', '{0} days', $days, $days);
}

// When time has passed
if (!$backwards && $relativeDate) {
return sprintf($options['relativeString'], $relativeDate);
}
if (!$backwards) {
$aboutAgo = [
'day' => __d('cake', 'about a day ago'),
'week' => __d('cake', 'about a week ago'),
'month' => __d('cake', 'about a month ago'),
'year' => __d('cake', 'about a year ago')
];

return $aboutAgo[$fWord];
}

// When time is to come
if (!$relativeDate) {
$aboutIn = [
'day' => __d('cake', 'in about a day'),
'week' => __d('cake', 'in about a week'),
'month' => __d('cake', 'in about a month'),
'year' => __d('cake', 'in about a year')
];

return $aboutIn[$fWord];
}

return $relativeDate;
return (new RelativeTimeFormatter($this))->dateAgoInWords($options);
}
}

0 comments on commit 1c6ac85

Please sign in to comment.