3 namespace Drupal\Tests\datetime\Kernel\Views;
5 use Drupal\Component\Datetime\DateTimePlus;
6 use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
7 use Drupal\field\Entity\FieldStorageConfig;
8 use Drupal\node\Entity\Node;
9 use Drupal\views\Views;
12 * Tests date-only fields.
16 class FilterDateTest extends DateTimeHandlerTestBase {
21 public static $testViews = ['test_filter_datetime'];
24 * An array of timezone extremes to test.
28 protected static $timezones = [
48 * Create nodes with relative dates of yesterday, today, and tomorrow.
50 protected function setUp($import_test_views = TRUE) {
51 parent::setUp($import_test_views);
53 // Change field storage to date-only.
54 $storage = FieldStorageConfig::load('node.' . static::$field_name);
55 $storage->setSetting('datetime_type', DateTimeItem::DATETIME_TYPE_DATE);
58 // Retrieve tomorrow, today and yesterday dates just to create the nodes.
59 $timestamp = $this->getUTCEquivalentOfUserNowAsTimestamp();
60 $dates = $this->getRelativeDateValuesFromTimestamp($timestamp);
62 // Clean the nodes on setUp.
64 foreach ($dates as $date) {
65 $node = Node::create([
66 'title' => $this->randomMachineName(8),
73 $this->nodes[] = $node;
78 * Test offsets with date-only fields.
80 public function testDateOffsets() {
81 $view = Views::getView('test_filter_datetime');
82 $field = static::$field_name . '_value';
84 foreach (static::$timezones as $timezone) {
86 $this->setSiteTimezone($timezone);
87 $timestamp = $this->getUTCEquivalentOfUserNowAsTimestamp();
88 $dates = $this->getRelativeDateValuesFromTimestamp($timestamp);
89 $this->updateNodesDateFieldsValues($dates);
91 // Test simple operations.
92 $view->initHandlers();
94 // A greater than or equal to 'now', should return the 'today' and the
96 $view->filter[$field]->operator = '>=';
97 $view->filter[$field]->value['type'] = 'offset';
98 $view->filter[$field]->value['value'] = 'now';
99 $view->setDisplay('default');
100 $this->executeView($view);
102 ['nid' => $this->nodes[0]->id()],
103 ['nid' => $this->nodes[1]->id()],
105 $this->assertIdenticalResultset($view, $expected_result, $this->map);
108 // Only dates in the past.
109 $view->initHandlers();
110 $view->filter[$field]->operator = '<';
111 $view->filter[$field]->value['type'] = 'offset';
112 $view->filter[$field]->value['value'] = 'now';
113 $view->setDisplay('default');
114 $this->executeView($view);
116 ['nid' => $this->nodes[2]->id()],
118 $this->assertIdenticalResultset($view, $expected_result, $this->map);
121 // Test offset for between operator. Only 'tomorrow' node should appear.
122 $view->initHandlers();
123 $view->filter[$field]->operator = 'between';
124 $view->filter[$field]->value['type'] = 'offset';
125 $view->filter[$field]->value['max'] = '+2 days';
126 $view->filter[$field]->value['min'] = '+1 day';
127 $view->setDisplay('default');
128 $this->executeView($view);
130 ['nid' => $this->nodes[0]->id()],
132 $this->assertIdenticalResultset($view, $expected_result, $this->map);
138 * Test date filter with date-only fields.
140 public function testDateIs() {
141 $view = Views::getView('test_filter_datetime');
142 $field = static::$field_name . '_value';
144 foreach (static::$timezones as $timezone) {
146 $this->setSiteTimezone($timezone);
147 $timestamp = $this->getUTCEquivalentOfUserNowAsTimestamp();
148 $dates = $this->getRelativeDateValuesFromTimestamp($timestamp);
149 $this->updateNodesDateFieldsValues($dates);
151 // Test simple operations.
152 $view->initHandlers();
154 // Filtering with nodes date-only values (format: Y-m-d) to test UTC
155 // conversion does NOT change the day.
156 $view->filter[$field]->operator = '=';
157 $view->filter[$field]->value['type'] = 'date';
158 $view->filter[$field]->value['value'] = $this->nodes[2]->field_date->first()->getValue()['value'];
159 $view->setDisplay('default');
160 $this->executeView($view);
162 ['nid' => $this->nodes[2]->id()],
164 $this->assertIdenticalResultset($view, $expected_result, $this->map);
167 // Test offset for between operator. Only 'today' and 'tomorrow' nodes
169 $view->initHandlers();
170 $view->filter[$field]->operator = 'between';
171 $view->filter[$field]->value['type'] = 'date';
172 $view->filter[$field]->value['max'] = $this->nodes[0]->field_date->first()->getValue()['value'];
173 $view->filter[$field]->value['min'] = $this->nodes[1]->field_date->first()->getValue()['value'];
174 $view->setDisplay('default');
175 $this->executeView($view);
177 ['nid' => $this->nodes[0]->id()],
178 ['nid' => $this->nodes[1]->id()],
180 $this->assertIdenticalResultset($view, $expected_result, $this->map);
186 * Returns UTC timestamp of user's TZ 'now'.
188 * The date field stores date_only values without conversion, considering them
189 * already as UTC. This method returns the UTC equivalent of user's 'now' as a
190 * unix timestamp, so they match using Y-m-d format.
195 protected function getUTCEquivalentOfUserNowAsTimestamp() {
196 $user_now = new DateTimePlus('now', new \DateTimeZone(drupal_get_user_timezone()));
197 $utc_equivalent = new DateTimePlus($user_now->format('Y-m-d H:i:s'), new \DateTimeZone(DATETIME_STORAGE_TIMEZONE));
199 return $utc_equivalent->getTimestamp();
203 * Returns an array formatted date_only values.
205 * @param int $timestamp
206 * Unix Timestamp equivalent to user's "now".
209 * An array of DATETIME_DATE_STORAGE_FORMAT date values. In order tomorrow,
210 * today and yesterday.
212 protected function getRelativeDateValuesFromTimestamp($timestamp) {
215 \Drupal::service('date.formatter')->format($timestamp + 86400, 'custom', DATETIME_DATE_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE),
217 \Drupal::service('date.formatter')->format($timestamp, 'custom', DATETIME_DATE_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE),
219 \Drupal::service('date.formatter')->format($timestamp - 86400, 'custom', DATETIME_DATE_STORAGE_FORMAT, DATETIME_STORAGE_TIMEZONE),
224 * Updates tests nodes date fields values.
226 * @param array $dates
227 * An array of DATETIME_DATE_STORAGE_FORMAT date values.
229 protected function updateNodesDateFieldsValues(array $dates) {
230 foreach ($dates as $index => $date) {
231 $this->nodes[$index]->{static::$field_name}->value = $date;
232 $this->nodes[$index]->save();