mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #3025 from tractorcow/pulls/3.2-date-relevance
API DateTime.Ago better infers significance of date units.
This commit is contained in:
commit
04e26d4a36
@ -221,9 +221,10 @@ class Date extends DBField {
|
||||
* 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".
|
||||
* @param int $significance Minimum significant value of X for "X units ago" to display
|
||||
* @return String
|
||||
*/
|
||||
public function Ago($includeSeconds = true) {
|
||||
public function Ago($includeSeconds = true, $significance = 2) {
|
||||
if($this->value) {
|
||||
$time = SS_Datetime::now()->Format('U');
|
||||
if(strtotime($this->value) == $time || $time > strtotime($this->value)) {
|
||||
@ -231,14 +232,14 @@ class Date extends DBField {
|
||||
'Date.TIMEDIFFAGO',
|
||||
"{difference} ago",
|
||||
'Natural language time difference, e.g. 2 hours ago',
|
||||
array('difference' => $this->TimeDiff($includeSeconds))
|
||||
array('difference' => $this->TimeDiff($includeSeconds, $significance))
|
||||
);
|
||||
} else {
|
||||
return _t(
|
||||
'Date.TIMEDIFFIN',
|
||||
"in {difference}",
|
||||
'Natural language time difference, e.g. in 2 hours',
|
||||
array('difference' => $this->TimeDiff($includeSeconds))
|
||||
array('difference' => $this->TimeDiff($includeSeconds, $significance))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -246,79 +247,68 @@ class Date extends DBField {
|
||||
|
||||
/**
|
||||
* @param boolean $includeSeconds Show seconds, or just round to "less than a minute".
|
||||
* @return String
|
||||
* @param int $significance Minimum significant value of X for "X units ago" to display
|
||||
* @return string
|
||||
*/
|
||||
public function TimeDiff($includeSeconds = true) {
|
||||
public function TimeDiff($includeSeconds = true, $significance = 2) {
|
||||
if(!$this->value) return false;
|
||||
|
||||
$time = SS_Datetime::now()->Format('U');
|
||||
$ago = abs($time - strtotime($this->value));
|
||||
if($ago < 60 && !$includeSeconds) {
|
||||
return _t('Date.LessThanMinuteAgo', 'less than a minute');
|
||||
} elseif($ago < $significance * 60 && $includeSeconds) {
|
||||
return $this->TimeDiffIn('seconds');
|
||||
} elseif($ago < $significance * 3600) {
|
||||
return $this->TimeDiffIn('minutes');
|
||||
} elseif($ago < $significance * 86400) {
|
||||
return $this->TimeDiffIn('hours');
|
||||
} elseif($ago < $significance * 86400 * 30) {
|
||||
return $this->TimeDiffIn('days');
|
||||
} elseif($ago < $significance * 86400 * 365) {
|
||||
return $this->TimeDiffIn('months');
|
||||
} else {
|
||||
return $this->TimeDiffIn('years');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time difference, but always returns it in a certain format
|
||||
*
|
||||
* @param string $format The format, could be one of these:
|
||||
* 'seconds', 'minutes', 'hours', 'days', 'months', 'years'.
|
||||
* @return string The resulting formatted period
|
||||
*/
|
||||
public function TimeDiffIn($format) {
|
||||
if(!$this->value) return false;
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time difference, but always returns it in a certain format
|
||||
* @param string $format The format, could be one of these:
|
||||
* 'seconds', 'minutes', 'hours', 'days', 'months', 'years'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function TimeDiffIn($format) {
|
||||
if($this->value) {
|
||||
$ago = abs(time() - strtotime($this->value));
|
||||
|
||||
switch($format) {
|
||||
case "seconds":
|
||||
$span = $ago;
|
||||
return ($span != 1) ? "{$span} seconds" : "{$span} second";
|
||||
break;
|
||||
return ($span != 1) ? "{$span} "._t("Date.SECS", "secs") : "{$span} "._t("Date.SEC", "sec");
|
||||
|
||||
case "minutes":
|
||||
$span = round($ago/60);
|
||||
return ($span != 1) ? "{$span} minutes" : "{$span} minute";
|
||||
break;
|
||||
return ($span != 1) ? "{$span} "._t("Date.MINS", "mins") : "{$span} "._t("Date.MIN", "min");
|
||||
|
||||
case "hours":
|
||||
$span = round($ago/3600);
|
||||
return ($span != 1) ? "{$span} hours" : "{$span} hour";
|
||||
break;
|
||||
return ($span != 1) ? "{$span} "._t("Date.HOURS", "hours") : "{$span} "._t("Date.HOUR", "hour");
|
||||
|
||||
case "days":
|
||||
$span = round($ago/86400);
|
||||
return ($span != 1) ? "{$span} days" : "{$span} day";
|
||||
break;
|
||||
return ($span != 1) ? "{$span} "._t("Date.DAYS", "days") : "{$span} "._t("Date.DAY", "day");
|
||||
|
||||
case "months":
|
||||
$span = round($ago/86400/30);
|
||||
return ($span != 1) ? "{$span} months" : "{$span} month";
|
||||
break;
|
||||
return ($span != 1) ? "{$span} "._t("Date.MONTHS", "months") : "{$span} "._t("Date.MONTH", "month");
|
||||
|
||||
case "years":
|
||||
$span = round($ago/86400/365);
|
||||
return ($span != 1) ? "{$span} years" : "{$span} year";
|
||||
break;
|
||||
}
|
||||
return ($span != 1) ? "{$span} "._t("Date.YEARS", "years") : "{$span} "._t("Date.YEAR", "year");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,30 @@ class DateTest extends SapphireTest {
|
||||
public function testAgoInPast() {
|
||||
SS_Datetime::set_mock_now('2000-12-31 12:00:00');
|
||||
|
||||
$this->assertEquals(
|
||||
'1 month ago',
|
||||
DBField::create_field('Date', '2000-11-26')->Ago(true, 1),
|
||||
'Past match on days, less than two months, lowest significance'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'50 days ago', // Rounded from 49.5 days up
|
||||
DBField::create_field('Date', '2000-11-12')->Ago(),
|
||||
'Past match on days, less than two months'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'2 months ago',
|
||||
DBField::create_field('Date', '2000-10-27')->Ago(),
|
||||
'Past match on days, over two months'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'66 days ago', // rounded from 65.5 days up
|
||||
DBField::create_field('Date', '2000-10-27')->Ago(true, 3),
|
||||
'Past match on days, over two months, significance of 3'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'10 years ago',
|
||||
DBField::create_field('Date', '1990-12-31')->Ago(),
|
||||
@ -177,6 +201,12 @@ class DateTest extends SapphireTest {
|
||||
|
||||
$this->assertEquals(
|
||||
'1 year ago',
|
||||
DBField::create_field('Date', '1999-12-30')->Ago(true, 1),
|
||||
'Approximate past match in singular, lowest significance'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'12 months ago',
|
||||
DBField::create_field('Date', '1999-12-30')->Ago(),
|
||||
'Approximate past match in singular'
|
||||
);
|
||||
@ -195,6 +225,12 @@ class DateTest extends SapphireTest {
|
||||
|
||||
$this->assertEquals(
|
||||
'in 1 day',
|
||||
DBField::create_field('Date', '2001-01-01')->Ago(true, 1),
|
||||
'Approximate past match on minutes'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'in 24 hours',
|
||||
DBField::create_field('Date', '2001-01-01')->Ago(),
|
||||
'Approximate past match on minutes'
|
||||
);
|
||||
|
@ -106,6 +106,12 @@ class SS_DatetimeTest extends SapphireTest {
|
||||
|
||||
$this->assertEquals(
|
||||
'1 year ago',
|
||||
DBField::create_field('SS_Datetime', '1999-12-30 12:00:12')->Ago(true, 1),
|
||||
'Approximate past match in singular, significance=1'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'12 months ago',
|
||||
DBField::create_field('SS_Datetime', '1999-12-30 12:00:12')->Ago(),
|
||||
'Approximate past match in singular'
|
||||
);
|
||||
@ -128,6 +134,36 @@ class SS_DatetimeTest extends SapphireTest {
|
||||
'Approximate past match on seconds with $includeSeconds=false'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'1 min ago',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 11:58:50')->Ago(false),
|
||||
'Test between 1 and 2 minutes with includeSeconds=false'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'70 secs ago',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 11:58:50')->Ago(true),
|
||||
'Test between 1 and 2 minutes with includeSeconds=true'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'4 mins ago',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 11:55:50')->Ago(),
|
||||
'Past match on minutes'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'1 hour ago',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 10:50:58')->Ago(true, 1),
|
||||
'Past match on hours, significance=1'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'3 hours ago',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 08:50:58')->Ago(),
|
||||
'Past match on hours'
|
||||
);
|
||||
|
||||
SS_Datetime::clear_mock_now();
|
||||
}
|
||||
|
||||
@ -142,6 +178,12 @@ class SS_DatetimeTest extends SapphireTest {
|
||||
|
||||
$this->assertEquals(
|
||||
'in 1 hour',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 1:01:05')->Ago(true, 1),
|
||||
'Approximate past match on minutes, significance=1'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'in 61 mins',
|
||||
DBField::create_field('SS_Datetime', '2000-12-31 1:01:05')->Ago(),
|
||||
'Approximate past match on minutes'
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user