diff --git a/core/modules/datetime/src/Plugin/views/filter/Date.php b/core/modules/datetime/src/Plugin/views/filter/Date.php index 56b3bf6..cc3caf7 100644 --- a/core/modules/datetime/src/Plugin/views/filter/Date.php +++ b/core/modules/datetime/src/Plugin/views/filter/Date.php @@ -2,7 +2,7 @@ /** * @file - * Contains \Drupal\datetime\Plugin\views\filter\String. + * Contains \Drupal\datetime\Plugin\views\filter\Date. */ namespace Drupal\datetime\Plugin\views\filter; @@ -13,6 +13,7 @@ use Drupal\views\FieldAPIHandlerTrait; use Drupal\views\Plugin\views\filter\Date as NumericDate; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RequestStack; /** * Date/time views filter. @@ -42,7 +43,14 @@ class Date extends NumericDate implements ContainerFactoryPluginInterface { * * @see \Drupal\views\Plugin\views\query\Sql::getDateFormat() */ - protected $dateFormat = 'Y-m-d H:i:s'; + protected $dateFormat = DATETIME_DATETIME_STORAGE_FORMAT; + + /** + * The request stack used to determin current time. + * + * @var \Symfony\Component\HttpFoundation\RequestStack + */ + protected $requestStack; /** * Constructs a new Date handler. @@ -55,15 +63,18 @@ class Date extends NumericDate implements ContainerFactoryPluginInterface { * The plugin implementation definition. * @param \Drupal\Core\Datetime\DateFormatter $date_formatter * The date formatter service. + * @param \Symfony\Component\HttpFoundation\RequestStack + * The request stack used to determine the current time. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatter $date_formatter) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, DateFormatter $date_formatter, RequestStack $request_stack) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->dateFormatter = $date_formatter; + $this->requestStack = $request_stack; // Date format depends on field storage format. $definition = $this->getFieldStorageDefinition(); if ($definition->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) { - $this->dateFormat = 'Y-m-d'; + $this->dateFormat = DATETIME_DATE_STORAGE_FORMAT; } } @@ -75,7 +86,8 @@ public static function create(ContainerInterface $container, array $configuratio $configuration, $plugin_id, $plugin_definition, - $container->get('date.formatter') + $container->get('date.formatter'), + $container->get('request_stack') ); } @@ -83,7 +95,7 @@ public static function create(ContainerInterface $container, array $configuratio * Override parent method, which deals with dates as integers. */ protected function opBetween($field) { - $origin = ($this->value['type'] == 'offset') ? REQUEST_TIME : 0; + $origin = ($this->value['type'] == 'offset') ? $this->requestStack->getCurrentRequest()->server->get('REQUEST_TIME') : 0; $a = intval(strtotime($this->value['min'], $origin)); $b = intval(strtotime($this->value['max'], $origin)); @@ -105,7 +117,7 @@ protected function opBetween($field) { * Override parent method, which deals with dates as integers. */ protected function opSimple($field) { - $origin = (!empty($this->value['type']) && $this->value['type'] == 'offset') ? REQUEST_TIME : 0; + $origin = (!empty($this->value['type']) && $this->value['type'] == 'offset') ? $this->requestStack->getCurrentRequest()->server->get('REQUEST_TIME') : 0; $value = intval(strtotime($this->value['value'], $origin)); // Convert to ISO. UTC is used since dates are stored in UTC. diff --git a/core/modules/datetime/src/Tests/Views/FilterDateTest.php b/core/modules/datetime/src/Tests/Views/FilterDateTest.php new file mode 100644 index 0000000..d36bc73 --- /dev/null +++ b/core/modules/datetime/src/Tests/Views/FilterDateTest.php @@ -0,0 +1,115 @@ +setSetting('datetime_type', DateTimeItem::DATETIME_TYPE_DATE); + $storage->save(); + + $dates = [ + // Tomorrow. + \Drupal::service('date.formatter')->format(static::$date + 86400, 'custom', DATETIME_DATE_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE), + // Today. + \Drupal::service('date.formatter')->format(static::$date, 'custom', DATETIME_DATE_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE), + // Yesterday. + \Drupal::service('date.formatter')->format(static::$date - 86400, 'custom', DATETIME_DATE_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE), + ]; + + foreach ($dates as $date) { + $this->nodes[] = $this->drupalCreateNode(array( + 'field_date' => array( + 'value' => $date, + ) + )); + } + } + + /** + * Test offsets with date-only fields. + */ + public function testDateOffsets() { + $view = Views::getView('test_filter_datetime'); + $field = static::$field_name . '_value'; + + // Test simple operations. + $view->initHandlers(); + + // A greater than or equal to 'now', should return the 'today' and + // the 'tomorrow' node. + $view->filter[$field]->operator = '>='; + $view->filter[$field]->value['type'] = 'offset'; + $view->filter[$field]->value['value'] = 'now'; + $view->setDisplay('default'); + $this->executeView($view); + $expected_result = array( + array('nid' => $this->nodes[0]->id()), + array('nid' => $this->nodes[1]->id()), + ); + $this->assertIdenticalResultset($view, $expected_result, $this->map); + $view->destroy(); + + // Only dates in the past. + $view->initHandlers(); + $view->filter[$field]->operator = '<'; + $view->filter[$field]->value['type'] = 'offset'; + $view->filter[$field]->value['value'] = 'now'; + $view->setDisplay('default'); + $this->executeView($view); + $expected_result = array( + array('nid' => $this->nodes[2]->id()), + ); + $this->assertIdenticalResultset($view, $expected_result, $this->map); + $view->destroy(); + + // Test offset for between operator. Only the 'tomorrow' node should appear. + $view->initHandlers(); + $view->filter[$field]->operator = 'between'; + $view->filter[$field]->value['type'] = 'offset'; + $view->filter[$field]->value['max'] = '+2 days'; + $view->filter[$field]->value['min'] = '+1 day'; + $view->setDisplay('default'); + $this->executeView($view); + $expected_result = array( + array('nid' => $this->nodes[0]->id()), + ); + $this->assertIdenticalResultset($view, $expected_result, $this->map); + } + +} diff --git a/core/modules/datetime/src/Tests/Views/FilterDateTimeTest.php b/core/modules/datetime/src/Tests/Views/FilterDateTimeTest.php index 068c88e..283caf6 100644 --- a/core/modules/datetime/src/Tests/Views/FilterDateTimeTest.php +++ b/core/modules/datetime/src/Tests/Views/FilterDateTimeTest.php @@ -45,9 +45,9 @@ public function setUp() { // Add some basic test nodes. $dates = array( - '2000-10-10', - '2001-10-10', - '2002-10-10', + '2000-10-10T00:01:30', + '2001-10-10T12:12:12', + '2002-10-10T14:14:14', // The date storage timezone is used (this mimics the steps taken in the // widget: \Drupal\datetime\Plugin\Field\FieldWidget::messageFormValues(). \Drupal::service('date.formatter')->format(static::$date, 'custom', DATETIME_DATETIME_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE), diff --git a/core/modules/views/src/Plugin/views/query/Sql.php b/core/modules/views/src/Plugin/views/query/Sql.php index fcc86be..a61b850 100644 --- a/core/modules/views/src/Plugin/views/query/Sql.php +++ b/core/modules/views/src/Plugin/views/query/Sql.php @@ -1802,7 +1802,6 @@ public function getDateFormat($field, $format, $string_date = FALSE) { } // In order to allow for partials (eg, only the year), transform to a // date, back to a string again. - // @todo this is very messy, and EXTRACT should probably be used. return "TO_CHAR(TO_TIMESTAMP($field, 'YYYY-MM-DD HH24:MI:SS'), '$format')"; case 'sqlite': $replace = array(