cleans up CakeTime::timeAgoInWords and adds option for custom futures string

This commit is contained in:
Schlaefer 2014-10-01 10:35:41 +02:00
parent af43bc1706
commit b96eb1fb46
2 changed files with 114 additions and 104 deletions

View file

@ -108,9 +108,9 @@ class CakeTimeTest extends CakeTestCase {
array('-2 days -3 hours', '2 days, 3 hours ago'),
array('-1 week', '1 week ago'),
array('-2 weeks -2 days', '2 weeks, 2 days ago'),
array('+1 week', '1 week'),
array('+1 week 1 day', '1 week, 1 day'),
array('+2 weeks 2 day', '2 weeks, 2 days'),
array('+1 week', 'in 1 week'),
array('+1 week 1 day', 'in 1 week, 1 day'),
array('+2 weeks 2 day', 'in 2 weeks, 2 days'),
array('2007-9-24', 'on 24/9/07'),
array('now', 'just now'),
);
@ -136,37 +136,37 @@ class CakeTimeTest extends CakeTestCase {
return array(
array(
'+4 months +2 weeks +3 days',
'4 months, 2 weeks, 3 days',
'in 4 months, 2 weeks, 3 days',
'8 years'
),
array(
'+4 months +2 weeks +1 day',
'4 months, 2 weeks, 1 day',
'in 4 months, 2 weeks, 1 day',
'8 years'
),
array(
'+3 months +2 weeks',
'3 months, 2 weeks',
'in 3 months, 2 weeks',
'8 years'
),
array(
'+3 months +2 weeks +1 day',
'3 months, 2 weeks, 1 day',
'in 3 months, 2 weeks, 1 day',
'8 years'
),
array(
'+1 months +1 week +1 day',
'1 month, 1 week, 1 day',
'in 1 month, 1 week, 1 day',
'8 years'
),
array(
'+2 months +2 days',
'2 months, 2 days',
'in 2 months, 2 days',
'on ' . date('j/n/y', strtotime('+2 months +2 days'))
),
array(
'+2 months +12 days',
'2 months, 1 week, 5 days',
'in 2 months, 1 week, 5 days',
'3 months'
),
);
@ -198,6 +198,13 @@ class CakeTimeTest extends CakeTestCase {
$expected = 'at least 8 years ago';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('relativeStringFuture' => 'not in the next %s', 'accuracy' => array('year' => 'year'), 'end' => '+10 years')
);
$expected = 'not in the next 8 years';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+4 months +2 weeks +3 days'),
array('absoluteString' => 'exactly on %s', 'accuracy' => array('year' => 'year'), 'end' => '+2 months')
@ -216,35 +223,35 @@ class CakeTimeTest extends CakeTestCase {
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'year'), 'end' => '+10 years')
);
$expected = '8 years';
$expected = 'in 8 years';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'month'), 'end' => '+10 years')
);
$expected = '8 years, 4 months';
$expected = 'in 8 years, 4 months';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'week'), 'end' => '+10 years')
);
$expected = '8 years, 4 months, 2 weeks';
$expected = 'in 8 years, 4 months, 2 weeks';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+8 years +4 months +2 weeks +3 days'),
array('accuracy' => array('year' => 'day'), 'end' => '+10 years')
);
$expected = '8 years, 4 months, 2 weeks, 3 days';
$expected = 'in 8 years, 4 months, 2 weeks, 3 days';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
strtotime('+1 years +5 weeks'),
array('accuracy' => array('year' => 'year'), 'end' => '+10 years')
);
$expected = '1 year';
$expected = 'in 1 year';
$this->assertEquals($expected, $result);
$result = $this->Time->timeAgoInWords(
@ -278,13 +285,13 @@ class CakeTimeTest extends CakeTestCase {
strtotime('+2 weeks +2 days'),
'Y-m-d'
);
$this->assertRegExp('/^2 weeks, [1|2] day(s)?$/', $result);
$this->assertRegExp('/^in 2 weeks, [1|2] day(s)?$/', $result);
$result = $this->Time->timeAgoInWords(
strtotime('+2 weeks +2 days'),
'%x'
);
$this->assertRegExp('/^2 weeks, [1|2] day(s)?$/', $result);
$this->assertRegExp('/^in 2 weeks, [1|2] day(s)?$/', $result);
$result = $this->Time->timeAgoInWords(
strtotime('+2 months +2 days'),

View file

@ -65,13 +65,13 @@ class CakeTime {
* @see CakeTime::timeAgoInWords()
*/
public static $wordAccuracy = array(
'year' => "day",
'month' => "day",
'week' => "day",
'day' => "hour",
'hour' => "minute",
'minute' => "minute",
'second' => "second",
'year' => 'day',
'month' => 'day',
'week' => 'day',
'day' => 'hour',
'hour' => 'minute',
'minute' => 'minute',
'second' => 'second',
);
/**
@ -713,9 +713,10 @@ class CakeTime {
* - minute => The format if minutes > 0 (default "minute")
* - second => The format if seconds > 0 (default "second")
* - `end` => The end of relative time telling
* - `relativeString` => The printf compatible string when outputting relative time
* - `relativeString` => The printf compatible string when outputting past relative time
* - `relativeStringFuture` => The printf compatible string when outputting future relative time
* - `absoluteString` => The printf compatible string when outputting absolute time
* - `userOffset` => Users offset from GMT (in hours) *Deprecated* use timezone intead.
* - `userOffset` => Users offset from GMT (in hours) *Deprecated* use timezone instead.
* - `timezone` => The user timezone the timestamp should be formatted in.
*
* Relative dates look something like this:
@ -737,13 +738,16 @@ class CakeTime {
*/
public static function timeAgoInWords($dateTime, $options = array()) {
$timezone = null;
$accuracies = self::$wordAccuracy;
$format = self::$wordFormat;
$end = self::$wordEnd;
$relativeString = __d('cake', '%s ago');
$relativeEnd = self::$wordEnd;
$relativeStringPast = __d('cake', '%s ago');
$relativeStringFuture = __d('cake', 'in %s');
$absoluteString = __d('cake', 'on %s');
$accuracy = self::$wordAccuracy;
if (is_array($options)) {
if (is_string($options)) {
$format = $options;
} elseif (!empty($options)) {
if (isset($options['timezone'])) {
$timezone = $options['timezone'];
} elseif (isset($options['userOffset'])) {
@ -752,10 +756,10 @@ class CakeTime {
if (isset($options['accuracy'])) {
if (is_array($options['accuracy'])) {
$accuracy = array_merge($accuracy, $options['accuracy']);
$accuracies = array_merge($accuracies, $options['accuracy']);
} else {
foreach ($accuracy as $key => $level) {
$accuracy[$key] = $options['accuracy'];
foreach ($accuracies as $key => $level) {
$accuracies[$key] = $options['accuracy'];
}
}
}
@ -764,51 +768,56 @@ class CakeTime {
$format = $options['format'];
}
if (isset($options['end'])) {
$end = $options['end'];
$relativeEnd = $options['end'];
}
if (isset($options['relativeString'])) {
$relativeString = $options['relativeString'];
$relativeStringPast = $options['relativeString'];
unset($options['relativeString']);
}
if (isset($options['relativeStringFuture'])) {
$relativeStringFuture = $options['relativeStringFuture'];
unset($options['relativeStringFuture']);
}
if (isset($options['absoluteString'])) {
$absoluteString = $options['absoluteString'];
unset($options['absoluteString']);
}
unset($options['end'], $options['format']);
} else {
$format = $options;
}
$now = self::fromString(time(), $timezone);
$inSeconds = self::fromString($dateTime, $timezone);
$backwards = ($inSeconds > $now);
$isFuture = ($inSeconds > $now);
$futureTime = $now;
$pastTime = $inSeconds;
if ($backwards) {
$futureTime = $inSeconds;
$pastTime = $now;
if ($isFuture) {
$startTime = $now;
$endTime = $inSeconds;
} else {
$startTime = $inSeconds;
$endTime = $now;
}
$diff = $futureTime - $pastTime;
$diff = $endTime - $startTime;
if (!$diff) {
if ($diff === 0) {
return __d('cake', 'just now', 'just now');
}
if ($diff > abs($now - self::fromString($end))) {
return sprintf($absoluteString,
(strpos($format, '%') === false) ?
date($format, $inSeconds) :
self::_strftime($format, $inSeconds)
);
$isAbsoluteDate = $diff > abs($now - self::fromString($relativeEnd));
if ($isAbsoluteDate) {
if (strpos($format, '%') === false) {
$date = date($format, $inSeconds);
} else {
$date = self::_strftime($format, $inSeconds);
}
return sprintf($absoluteString, $date);
}
$years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
// 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));
$years = $months = $weeks = $days = $hours = $minutes = $seconds = 0;
list($future['H'], $future['i'], $future['s'], $future['d'], $future['m'], $future['Y']) = explode('/', date('H/i/s/d/m/Y', $endTime));
list($past['H'], $past['i'], $past['s'], $past['d'], $past['m'], $past['Y']) = explode('/', date('H/i/s/d/m/Y', $startTime));
$years = $future['Y'] - $past['Y'];
$months = $future['m'] + ((12 * $years) - $past['m']);
@ -824,13 +833,13 @@ class CakeTime {
if ($future['d'] >= $past['d']) {
$days = $future['d'] - $past['d'];
} else {
$daysInPastMonth = date('t', $pastTime);
$daysInPastMonth = date('t', $startTime);
$daysInFutureMonth = date('t', mktime(0, 0, 0, $future['m'] - 1, 1, $future['Y']));
if (!$backwards) {
$days = ($daysInPastMonth - $past['d']) + $future['d'];
} else {
if ($isFuture) {
$days = ($daysInFutureMonth - $past['d']) + $future['d'];
} else {
$days = ($daysInPastMonth - $past['d']) + $future['d'];
}
if ($future['m'] != $past['m']) {
@ -853,9 +862,7 @@ class CakeTime {
$days = $days - ($weeks * 7);
}
} else {
$years = $months = $weeks = 0;
$days = floor($diff / 86400);
$diff = $diff - ($days * 86400);
$hours = floor($diff / 3600);
@ -863,69 +870,58 @@ class CakeTime {
$minutes = floor($diff / 60);
$diff = $diff - ($minutes * 60);
$seconds = $diff;
}
$fWord = $accuracy['second'];
$accuracy = $accuracies['second'];
if ($years > 0) {
$fWord = $accuracy['year'];
$accuracy = $accuracies['year'];
} elseif (abs($months) > 0) {
$fWord = $accuracy['month'];
$accuracy = $accuracies['month'];
} elseif (abs($weeks) > 0) {
$fWord = $accuracy['week'];
$accuracy = $accuracies['week'];
} elseif (abs($days) > 0) {
$fWord = $accuracy['day'];
$accuracy = $accuracies['day'];
} elseif (abs($hours) > 0) {
$fWord = $accuracy['hour'];
$accuracy = $accuracies['hour'];
} elseif (abs($minutes) > 0) {
$fWord = $accuracy['minute'];
$accuracy = $accuracies['minute'];
}
$fNum = str_replace(array('year', 'month', 'week', 'day', 'hour', 'minute', 'second'), array(1, 2, 3, 4, 5, 6, 7), $fWord);
$accuracyNum = str_replace(array('year', 'month', 'week', 'day', 'hour', 'minute', 'second'), array(1, 2, 3, 4, 5, 6, 7), $accuracy);
$relativeDate = '';
if ($fNum >= 1 && $years > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d year', '%d years', $years, $years);
$relativeDate = [];
if ($accuracyNum >= 1 && $years > 0) {
$relativeDate[] = __dn('cake', '%d year', '%d years', $years, $years);
}
if ($fNum >= 2 && $months > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d month', '%d months', $months, $months);
if ($accuracyNum >= 2 && $months > 0) {
$relativeDate[] = __dn('cake', '%d month', '%d months', $months, $months);
}
if ($fNum >= 3 && $weeks > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d week', '%d weeks', $weeks, $weeks);
if ($accuracyNum >= 3 && $weeks > 0) {
$relativeDate[] = __dn('cake', '%d week', '%d weeks', $weeks, $weeks);
}
if ($fNum >= 4 && $days > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d day', '%d days', $days, $days);
if ($accuracyNum >= 4 && $days > 0) {
$relativeDate[] = __dn('cake', '%d day', '%d days', $days, $days);
}
if ($fNum >= 5 && $hours > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d hour', '%d hours', $hours, $hours);
if ($accuracyNum >= 5 && $hours > 0) {
$relativeDate[] = __dn('cake', '%d hour', '%d hours', $hours, $hours);
}
if ($fNum >= 6 && $minutes > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d minute', '%d minutes', $minutes, $minutes);
if ($accuracyNum >= 6 && $minutes > 0) {
$relativeDate[] = __dn('cake', '%d minute', '%d minutes', $minutes, $minutes);
}
if ($fNum >= 7 && $seconds > 0) {
$relativeDate .= ($relativeDate ? ', ' : '') . __dn('cake', '%d second', '%d seconds', $seconds, $seconds);
if ($accuracyNum >= 7 && $seconds > 0) {
$relativeDate[] = __dn('cake', '%d second', '%d seconds', $seconds, $seconds);
}
$relativeDate = implode(', ', $relativeDate);
// When time has passed
if (!$backwards && $relativeDate) {
if ($relativeDate) {
$relativeString = ($isFuture) ? $relativeStringFuture : $relativeStringPast;
return sprintf($relativeString, $relativeDate);
}
if (!$backwards) {
$aboutAgo = array(
'second' => __d('cake', 'about a second ago'),
'minute' => __d('cake', 'about a minute ago'),
'hour' => __d('cake', 'about an hour ago'),
'day' => __d('cake', 'about a day ago'),
'week' => __d('cake', 'about a week ago'),
'year' => __d('cake', 'about a year ago')
);
return $aboutAgo[$fWord];
}
// When time is to come
if (!$relativeDate) {
$aboutIn = array(
if ($isFuture) {
$strings = array(
'second' => __d('cake', 'in about a second'),
'minute' => __d('cake', 'in about a minute'),
'hour' => __d('cake', 'in about an hour'),
@ -933,11 +929,18 @@ class CakeTime {
'week' => __d('cake', 'in about a week'),
'year' => __d('cake', 'in about a year')
);
return $aboutIn[$fWord];
} else {
$strings = array(
'second' => __d('cake', 'about a second ago'),
'minute' => __d('cake', 'about a minute ago'),
'hour' => __d('cake', 'about an hour ago'),
'day' => __d('cake', 'about a day ago'),
'week' => __d('cake', 'about a week ago'),
'year' => __d('cake', 'about a year ago')
);
}
return $relativeDate;
return $strings[$accuracy];
}
/**