浏览代码

Merge pull request #7789 from cakephp/relative-date-compat

Use the diffFormatter hook provided by chronos
José Lorenzo Rodríguez 10 年之前
父节点
当前提交
4b0d0f9d21

+ 1 - 1
src/I18n/Date.php

@@ -130,6 +130,6 @@ class Date extends MutableDate implements JsonSerializable
      */
     public function timeAgoInWords(array $options = [])
     {
-        return RelativeTimeFormatter::dateAgoInWords($this, $options);
+        return $this->diffFormatter()->dateAgoInWords($this, $options);
     }
 }

+ 18 - 0
src/I18n/DateFormatTrait.php

@@ -350,6 +350,24 @@ trait DateFormatTrait
     }
 
     /**
+     * Get the difference formatter instance or overwrite the current one.
+     *
+     * @param \Cake\I18n\RelativeTimeFormatter|null $formatter The formatter instance when setting.
+     * @return \Cake\I18n\RelativeTimeFormatter The formatter instance.
+     */
+    public static function diffFormatter($formatter = null)
+    {
+        if ($formatter === null) {
+            // Use the static property defined in chronos.
+            if (static::$diffFormatter === null) {
+                static::$diffFormatter = new RelativeTimeFormatter();
+            }
+            return static::$diffFormatter;
+        }
+        return static::$diffFormatter = $translator;
+    }
+
+    /**
      * Returns the data that should be displayed when debugging this object
      *
      * @return array

+ 1 - 1
src/I18n/FrozenDate.php

@@ -132,6 +132,6 @@ class FrozenDate extends ChronosDate implements JsonSerializable
      */
     public function timeAgoInWords(array $options = [])
     {
-        return RelativeTimeFormatter::dateAgoInWords($this, $options);
+        return $this->diffFormatter()->dateAgoInWords($this, $options);
     }
 }

+ 1 - 1
src/I18n/FrozenTime.php

@@ -154,7 +154,7 @@ class FrozenTime extends Chronos implements JsonSerializable
      */
     public function timeAgoInWords(array $options = [])
     {
-        return RelativeTimeFormatter::timeAgoInWords($this, $options);
+        return $this->diffFormatter()->timeAgoInWords($this, $options);
     }
 
     /**

+ 67 - 8
src/I18n/RelativeTimeFormatter.php

@@ -14,6 +14,7 @@
  */
 namespace Cake\I18n;
 
+use Cake\Chronos\ChronosInterface;
 use DatetimeInterface;
 
 /**
@@ -24,6 +25,64 @@ use DatetimeInterface;
 class RelativeTimeFormatter
 {
     /**
+     * Get the difference in a human readable format.
+     *
+     * @param \Cake\Chronos\ChronosInterface $date The datetime to start with.
+     * @param \Cake\Chronos\ChronosInterface|null $other The datetime to compare against.
+     * @param bool $absolute removes time difference modifiers ago, after, etc
+     * @return string The difference between the two days in a human readable format
+     * @see Cake\Chronos\ChronosInterface::diffForHumans
+     */
+    public function diffForHumans(ChronosInterface $date, ChronosInterface $other = null, $absolute = false)
+    {
+        $isNow = $other === null;
+        if ($isNow) {
+            $other = $date->now($date->tz);
+        }
+        $diffInterval = $date->diff($other);
+
+        switch (true) {
+            case ($diffInterval->y > 0):
+                $count = $diffInterval->y;
+                $message = __dn('cake', '{0} year', '{0} years', $count, $count);
+                break;
+            case ($diffInterval->m > 0):
+                $count = $diffInterval->m;
+                $message = __dn('cake', '{0} month', '{0} months', $count, $count);
+                break;
+            case ($diffInterval->d > 0):
+                $count = $diffInterval->d;
+                if ($count >= ChronosInterface::DAYS_PER_WEEK) {
+                    $count = (int)($count / ChronosInterface::DAYS_PER_WEEK);
+                    $message = __dn('cake', '{0} week', '{0} weeks', $count, $count);
+                } else {
+                    $message = __dn('cake', '{0} day', '{0} days', $count, $count);
+                }
+                break;
+            case ($diffInterval->h > 0):
+                $count = $diffInterval->h;
+                $message = __dn('cake', '{0} hour', '{0} hours', $count, $count);
+                break;
+            case ($diffInterval->i > 0):
+                $count = $diffInterval->i;
+                $message = __dn('cake', '{0} minute', '{0} minutes', $count, $count);
+                break;
+            default:
+                $count = $diffInterval->s;
+                $message = __dn('cake', '{0} second', '{0} seconds', $count, $count);
+                break;
+        }
+        if ($absolute) {
+            return $message;
+        }
+        $isFuture = $diffInterval->invert === 1;
+        if ($isNow) {
+            return $isFuture ? __d('cake', '{0} from now', $message) : __d('cake', '{0} ago', $message);
+        }
+        return $isFuture ? __d('cake', '{0} after', $message) : __d('cake', '{0} before', $message);
+    }
+
+    /**
      * Format a into a relative timestring.
      *
      * @param \DateTimeInterface $time The time instance to format.
@@ -31,9 +90,9 @@ class RelativeTimeFormatter
      * @return string Relative time string.
      * @see Cake\I18n\Time::timeAgoInWords()
      */
-    public static function timeAgoInWords(DatetimeInterface $time, array $options = [])
+    public function timeAgoInWords(DatetimeInterface $time, array $options = [])
     {
-        $options = static::_options($options, FrozenTime::class);
+        $options = $this->_options($options, FrozenTime::class);
         if ($options['timezone']) {
             $time = $time->timezone($options['timezone']);
         }
@@ -58,7 +117,7 @@ class RelativeTimeFormatter
             return sprintf($options['absoluteString'], $time->i18nFormat($options['format']));
         }
 
-        $diffData = static::_diffData($futureTime, $pastTime, $backwards, $options);
+        $diffData = $this->_diffData($futureTime, $pastTime, $backwards, $options);
         list($fNum, $fWord, $years, $months, $weeks, $days, $hours, $minutes, $seconds) = array_values($diffData);
 
         $relativeDate = [];
@@ -122,7 +181,7 @@ class RelativeTimeFormatter
      * @param array $options An array of options.
      * @return array An array of values.
      */
-    protected static function _diffData($futureTime, $pastTime, $backwards, $options)
+    protected function _diffData($futureTime, $pastTime, $backwards, $options)
     {
         $diff = $futureTime - $pastTime;
 
@@ -216,9 +275,9 @@ class RelativeTimeFormatter
      * @return string Relative date string.
      * @see Cake\I18n\Date::timeAgoInWords()
      */
-    public static function dateAgoInWords(DatetimeInterface $date, array $options = [])
+    public function dateAgoInWords(DatetimeInterface $date, array $options = [])
     {
-        $options = static::_options($options, FrozenDate::class);
+        $options = $this->_options($options, FrozenDate::class);
         if ($options['timezone']) {
             $date = $date->timezone($options['timezone']);
         }
@@ -243,7 +302,7 @@ class RelativeTimeFormatter
             return sprintf($options['absoluteString'], $date->i18nFormat($options['format']));
         }
 
-        $diffData = static::_diffData($futureTime, $pastTime, $backwards, $options);
+        $diffData = $this->_diffData($futureTime, $pastTime, $backwards, $options);
         list($fNum, $fWord, $years, $months, $weeks, $days, $hours, $minutes, $seconds) = array_values($diffData);
 
         $relativeDate = [];
@@ -292,7 +351,7 @@ class RelativeTimeFormatter
      * @param string $class The class name to use for defaults.
      * @return array Options with defaults applied.
      */
-    protected static function _options($options, $class)
+    protected function _options($options, $class)
     {
         $options += [
             'from' => $class::now(),

+ 1 - 1
src/I18n/Time.php

@@ -153,7 +153,7 @@ class Time extends MutableDateTime implements JsonSerializable
      */
     public function timeAgoInWords(array $options = [])
     {
-        return RelativeTimeFormatter::timeAgoInWords($this, $options);
+        return $this->diffFormatter()->timeAgoInWords($this, $options);
     }
 
     /**

+ 55 - 0
tests/TestCase/I18n/TimeTest.php

@@ -607,6 +607,7 @@ class TimeTest extends TestCase
     public function testDiffForHumans($class)
     {
         $time = new $class('2014-04-20 10:10:10');
+
         $other = new $class('2014-04-27 10:10:10');
         $this->assertEquals('1 week before', $time->diffForHumans($other));
 
@@ -615,6 +616,60 @@ class TimeTest extends TestCase
 
         $other = new $class('2014-04-13 09:10:10');
         $this->assertEquals('1 week after', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-06 09:10:10');
+        $this->assertEquals('2 weeks after', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-21 10:10:10');
+        $this->assertEquals('1 day before', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-22 10:10:10');
+        $this->assertEquals('2 days before', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-20 10:11:10');
+        $this->assertEquals('1 minute before', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-20 10:12:10');
+        $this->assertEquals('2 minutes before', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-20 10:10:09');
+        $this->assertEquals('1 second after', $time->diffForHumans($other));
+
+        $other = new $class('2014-04-20 10:10:08');
+        $this->assertEquals('2 seconds after', $time->diffForHumans($other));
+    }
+
+    /**
+     * Tests diffForHumans absolute
+     *
+     * @dataProvider classNameProvider
+     * @return void
+     */
+    public function testDiffForHumansAbsolute($class)
+    {
+        $time = new $class('2014-04-20 10:10:10');
+        $this->assertEquals('1 year', $time->diffForHumans(null, ['absolute' => true]));
+
+        $other = new $class('2014-04-27 10:10:10');
+        $this->assertEquals('1 week', $time->diffForHumans($other, ['absolute' => true]));
+
+        $time = new $class('2016-04-20 10:10:10');
+        $this->assertEquals('4 months', $time->diffForHumans(null, ['absolute' => true]));
+    }
+
+    /**
+     * Tests diffForHumans with now
+     *
+     * @dataProvider classNameProvider
+     * @return void
+     */
+    public function testDiffForHumansNow($class)
+    {
+        $time = new $class('2014-04-20 10:10:10');
+        $this->assertEquals('1 year ago', $time->diffForHumans());
+
+        $time = new $class('2016-04-20 10:10:10');
+        $this->assertEquals('4 months from now', $time->diffForHumans());
     }
 
     /**