diff --git a/CHANGELOG.md b/CHANGELOG.md
index b81797e0a..3fd8d3a00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
* **Build 297** (2015-09-16)
+ - Added `timetense` list column type (see Backend > Lists docs), along with `|time_since` and `|time_tense` Twig filters.
- Fixed a bug in deferred binding that allowed repeat bindings and ignored add/delete pairs.
* **Build 293** (2015-09-07)
diff --git a/modules/backend/controllers/auth/signin.htm b/modules/backend/controllers/auth/signin.htm
index 4271bcdf0..19ca02928 100644
--- a/modules/backend/controllers/auth/signin.htm
+++ b/modules/backend/controllers/auth/signin.htm
@@ -26,10 +26,10 @@
autocomplete="off"
maxlength="255" />
-
-
+
+
diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php
index f500abeb7..16fc21033 100644
--- a/modules/backend/widgets/Lists.php
+++ b/modules/backend/widgets/Lists.php
@@ -11,6 +11,7 @@ use DbDongle;
use Carbon\Carbon;
use October\Rain\Html\Helper as HtmlHelper;
use October\Rain\Router\Helper as RouterHelper;
+use System\Helpers\DateTime as DateTimeHelper;
use Backend\Classes\ListColumn;
use Backend\Classes\WidgetBase;
use ApplicationException;
@@ -946,7 +947,21 @@ class Lists extends WidgetBase
$value = $this->validateDateTimeValue($value, $column);
- return $value->diffForHumans();
+ return DateTimeHelper::timeSince($value);
+ }
+
+ /**
+ * Process as time as current tense (Today at 0:00)
+ */
+ protected function evalTimetenseTypeValue($record, $column, $value)
+ {
+ if ($value === null) {
+ return null;
+ }
+
+ $value = $this->validateDateTimeValue($value, $column);
+
+ return DateTimeHelper::timeTense($value);
}
/**
@@ -954,9 +969,7 @@ class Lists extends WidgetBase
*/
protected function validateDateTimeValue($value, $column)
{
- if ($value instanceof DateTime) {
- $value = Carbon::instance($value);
- }
+ $value = DateTimeHelper::instance()->makeCarbon($value, false);
if (!$value instanceof Carbon) {
throw new ApplicationException(Lang::get(
diff --git a/modules/system/ServiceProvider.php b/modules/system/ServiceProvider.php
index 601db58f1..c0eb14170 100644
--- a/modules/system/ServiceProvider.php
+++ b/modules/system/ServiceProvider.php
@@ -178,6 +178,8 @@ class ServiceProvider extends ModuleServiceProvider
'trans' => ['Lang', 'get'],
'transchoice' => ['Lang', 'choice'],
'md' => ['Markdown', 'parse'],
+ 'time_since' => ['System\Helpers\DateTime', 'timeSince'],
+ 'time_tense' => ['System\Helpers\DateTime', 'timeTense'],
]);
});
}
diff --git a/modules/system/helpers/DateTime.php b/modules/system/helpers/DateTime.php
new file mode 100644
index 000000000..26930e867
--- /dev/null
+++ b/modules/system/helpers/DateTime.php
@@ -0,0 +1,80 @@
+makeCarbon($datetime)
+ ->diffForHumans()
+ ;
+ }
+
+ /**
+ * Returns 24-hour time and the day using the grammatical tense
+ * of the current time. Eg: Today at 12:49, Yesterday at 4:00
+ * or 18 Sep 2015 at 14:33.
+ *
+ * @return string
+ */
+ public static function timeTense($datetime)
+ {
+ $datetime = self::instance()->makeCarbon($datetime);
+ $yesterday = $datetime->subDays(1);
+ $tomorrow = $datetime->addDays(1);
+ $time = $datetime->format('H:i');
+ $date = $datetime->format('j M Y');
+
+ if ($datetime->isToday()) {
+ $date = 'Today';
+ }
+ elseif ($datetime->isYesterday()) {
+ $date = 'Yesterday';
+ }
+ elseif ($datetime->isTomorrow()) {
+ $date = 'Tomorrow';
+ }
+
+ return $date.' at '.$time;
+ }
+
+ /**
+ * Converts mixed inputs to a Carbon object.
+ *
+ * @return Carbon\Carbon
+ */
+ public function makeCarbon($value, $throwException = true)
+ {
+ if ($value instanceof Carbon) {
+ // Do nothing
+ }
+ elseif ($value instanceof PhpDateTime) {
+ $value = Carbon::instance($value);
+ }
+ elseif (is_numeric($value)) {
+ $value = Carbon::createFromTimestamp($value);
+ }
+ elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $value)) {
+ $value = Carbon::createFromFormat('Y-m-d', $value)->startOfDay();
+ }
+
+ if (!$value instanceof Carbon && $throwException) {
+ throw new Exception('Invalid date value supplied to DateTime helper.');
+ }
+
+ return $value;
+ }
+}