From 7e4629073a267d732591472ae7c0f91a44b43208 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Thu, 13 Dec 2012 19:01:27 +0100 Subject: [PATCH] NEW Date->Ago() with "less than a minute" support --- model/fieldtypes/Date.php | 76 ++++++++++++++++++++---------------- tests/model/DateTest.php | 42 ++++++++++++++++++++ tests/model/DatetimeTest.php | 60 ++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 33 deletions(-) diff --git a/model/fieldtypes/Date.php b/model/fieldtypes/Date.php index f789dd82c..a4c4dc31a 100644 --- a/model/fieldtypes/Date.php +++ b/model/fieldtypes/Date.php @@ -197,58 +197,68 @@ class Date extends DBField { } /** - * Returns the number of seconds/minutes/hours/days or months since the timestamp + * Returns the number of seconds/minutes/hours/days or months since the timestamp. + * + * @param boolean $includeSeconds Show seconds, or just round to "less than a minute". + * @return String */ - public function Ago() { + public function Ago($includeSeconds = true) { if($this->value) { - if(strtotime($this->value) == time() || time() > strtotime($this->value)) { + $time = SS_Datetime::now()->Format('U'); + if(strtotime($this->value) == $time || $time > strtotime($this->value)) { return _t( 'Date.TIMEDIFFAGO', "{difference} ago", 'Natural language time difference, e.g. 2 hours ago', - array('difference' => $this->TimeDiff()) + array('difference' => $this->TimeDiff($includeSeconds)) ); } else { return _t( 'Date.TIMEDIFFIN', "in {difference}", 'Natural language time difference, e.g. in 2 hours', - array('difference' => $this->TimeDiff()) + array('difference' => $this->TimeDiff($includeSeconds)) ); } } } - public function TimeDiff() { + /** + * @param boolean $includeSeconds Show seconds, or just round to "less than a minute". + * @return String + */ + public function TimeDiff($includeSeconds = true) { + if(!$this->value) return false; - if($this->value) { - $ago = abs(time() - strtotime($this->value)); - - if($ago < 60) { - $span = $ago; - return ($span != 1) ? "{$span} "._t("Date.SECS", " secs") : "{$span} "._t("Date.SEC", " sec"); - } - if($ago < 3600) { - $span = round($ago/60); - return ($span != 1) ? "{$span} "._t("Date.MINS", " mins") : "{$span} "._t("Date.MIN", " min"); - } - if($ago < 86400) { - $span = round($ago/3600); - return ($span != 1) ? "{$span} "._t("Date.HOURS", " hours") : "{$span} "._t("Date.HOUR", " hour"); - } - if($ago < 86400*30) { - $span = round($ago/86400); - return ($span != 1) ? "{$span} "._t("Date.DAYS", " days") : "{$span} "._t("Date.DAY", " day"); - } - if($ago < 86400*365) { - $span = round($ago/86400/30); - return ($span != 1) ? "{$span} "._t("Date.MONTHS", " months") : "{$span} "._t("Date.MONTH", " month"); - } - if($ago > 86400*365) { - $span = round($ago/86400/365); - return ($span != 1) ? "{$span} "._t("Date.YEARS", " years") : "{$span} "._t("Date.YEAR", " year"); - } + $time = SS_Datetime::now()->Format('U'); + $ago = abs($time - strtotime($this->value)); + + if($ago < 60 && $includeSeconds) { + $span = $ago; + $result = ($span != 1) ? "{$span} "._t("Date.SECS", "secs") : "{$span} "._t("Date.SEC", "sec"); + } elseif($ago < 60) { + $result = _t('Date.LessThanMinuteAgo', 'less than a minute'); + } elseif($ago < 3600) { + $span = round($ago/60); + $result = ($span != 1) ? "{$span} "._t("Date.MINS", "mins") : "{$span} "._t("Date.MIN", "min"); + } elseif($ago < 86400) { + $span = round($ago/3600); + $result = ($span != 1) ? "{$span} "._t("Date.HOURS", "hours") : "{$span} "._t("Date.HOUR", "hour"); + } elseif($ago < 86400*30) { + $span = round($ago/86400); + $result = ($span != 1) ? "{$span} "._t("Date.DAYS", "days") : "{$span} "._t("Date.DAY", "day"); + } elseif($ago < 86400*365) { + $span = round($ago/86400/30); + $result = ($span != 1) ? "{$span} "._t("Date.MONTHS", "months") : "{$span} "._t("Date.MONTH", "month"); + } elseif($ago > 86400*365) { + $span = round($ago/86400/365); + $result = ($span != 1) ? "{$span} "._t("Date.YEARS", "years") : "{$span} "._t("Date.YEAR", "year"); } + + // Replace duplicate spaces, backwards compat with existing translations + $result = preg_replace('/\s+/', ' ', $result); + + return $result; } /** diff --git a/tests/model/DateTest.php b/tests/model/DateTest.php index 11fbed9c4..1e805c2ca 100644 --- a/tests/model/DateTest.php +++ b/tests/model/DateTest.php @@ -160,4 +160,46 @@ class DateTest extends SapphireTest { $this->assertEquals('03 Apr 3000', $date->Format('d M Y')); } + public function testAgoInPast() { + SS_Datetime::set_mock_now('2000-12-31 12:00:00'); + + $this->assertEquals( + '10 years ago', + DBField::create_field('Date', '1990-12-31')->Ago(), + 'Exact past match on years' + ); + + $this->assertEquals( + '10 years ago', + DBField::create_field('Date', '1990-12-30')->Ago(), + 'Approximate past match on years' + ); + + $this->assertEquals( + '1 year ago', + DBField::create_field('Date', '1999-12-30')->Ago(), + 'Approximate past match in singular' + ); + + SS_Datetime::clear_mock_now(); + } + + public function testAgoInFuture() { + SS_Datetime::set_mock_now('2000-12-31 00:00:00'); + + $this->assertEquals( + 'in 100 years', + DBField::create_field('Date', '2100-12-31')->Ago(), + 'Exact past match on years' + ); + + $this->assertEquals( + 'in 1 day', + DBField::create_field('Date', '2001-01-01')->Ago(), + 'Approximate past match on minutes' + ); + + SS_Datetime::clear_mock_now(); + } + } diff --git a/tests/model/DatetimeTest.php b/tests/model/DatetimeTest.php index b078a9ed6..12246bc29 100644 --- a/tests/model/DatetimeTest.php +++ b/tests/model/DatetimeTest.php @@ -89,4 +89,64 @@ class SS_DatetimeTest extends SapphireTest { $this->assertEquals('2001-12-31%2022:10:59', $date->URLDateTime()); } + public function testAgoInPast() { + SS_Datetime::set_mock_now('2000-12-31 12:00:00'); + + $this->assertEquals( + '10 years ago', + DBField::create_field('SS_Datetime', '1990-12-31 12:00:00')->Ago(), + 'Exact past match on years' + ); + + $this->assertEquals( + '10 years ago', + DBField::create_field('SS_Datetime', '1990-12-30 12:00:00')->Ago(), + 'Approximate past match on years' + ); + + $this->assertEquals( + '1 year ago', + DBField::create_field('SS_Datetime', '1999-12-30 12:00:12')->Ago(), + 'Approximate past match in singular' + ); + + $this->assertEquals( + '50 mins ago', + DBField::create_field('SS_Datetime', '2000-12-31 11:10:11')->Ago(), + 'Approximate past match on minutes' + ); + + $this->assertEquals( + '59 secs ago', + DBField::create_field('SS_Datetime', '2000-12-31 11:59:01')->Ago(), + 'Approximate past match on seconds' + ); + + $this->assertEquals( + 'less than a minute ago', + DBField::create_field('SS_Datetime', '2000-12-31 11:59:01')->Ago(false), + 'Approximate past match on seconds with $includeSeconds=false' + ); + + SS_Datetime::clear_mock_now(); + } + + public function testAgoInFuture() { + SS_Datetime::set_mock_now('2000-12-31 00:00:00'); + + $this->assertEquals( + 'in 100 years', + DBField::create_field('SS_Datetime', '2100-12-31 12:00:00')->Ago(), + 'Exact past match on years' + ); + + $this->assertEquals( + 'in 1 hour', + DBField::create_field('SS_Datetime', '2000-12-31 1:01:05')->Ago(), + 'Approximate past match on minutes' + ); + + SS_Datetime::clear_mock_now(); + } + }