diff --git a/core/modules/datetime/src/DateTimeComputed.php b/core/modules/datetime/src/DateTimeComputed.php index 6939994b415c60f83f0e2fc3b212b276507f534b..9320bafa42db7746a70921c7f3dc22efa2417825 100644 --- a/core/modules/datetime/src/DateTimeComputed.php +++ b/core/modules/datetime/src/DateTimeComputed.php @@ -2,6 +2,7 @@ namespace Drupal\datetime; +use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\TypedData\DataDefinitionInterface; use Drupal\Core\TypedData\TypedDataInterface; @@ -40,14 +41,28 @@ public function getValue($langcode = NULL) { return $this->date; } + /** @var \Drupal\Core\Field\FieldItemInterface $item */ $item = $this->getParent(); $value = $item->{($this->definition->getSetting('date source'))}; - $storage_format = $item->getFieldDefinition()->getSetting('datetime_type') == 'date' ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT; + $datetime_type = $item->getFieldDefinition()->getSetting('datetime_type'); + $storage_format = $datetime_type === DateTimeItem::DATETIME_TYPE_DATE ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT; try { $date = DrupalDateTime::createFromFormat($storage_format, $value, DATETIME_STORAGE_TIMEZONE); if ($date instanceof DrupalDateTime && !$date->hasErrors()) { $this->date = $date; + // If the format did not include an explicit time portion, then the + // time will be set from the current time instead. For consistency, we + // set the time to 12:00:00 UTC for date-only fields. This is used so + // that the local date portion is the same, across nearly all time + // zones. + // @see datetime_date_default_time() + // @see http://php.net/manual/en/datetime.createfromformat.php + // @todo Update comment and/or code per the chosen solution in + // https://www.drupal.org/node/2830094 + if ($datetime_type === DateTimeItem::DATETIME_TYPE_DATE) { + $this->date->setTime(12, 0, 0); + } } } catch (\Exception $e) { diff --git a/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php b/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php new file mode 100644 index 0000000000000000000000000000000000000000..67e1b9d7646d7915a4403582be3a9170c612b9ec --- /dev/null +++ b/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php @@ -0,0 +1,105 @@ +fieldStorage = FieldStorageConfig::create([ + 'field_name' => Unicode::strtolower($this->randomMachineName()), + 'entity_type' => 'entity_test', + 'type' => 'daterange', + 'settings' => ['datetime_type' => DateRangeItem::DATETIME_TYPE_DATE], + ]); + $this->fieldStorage->save(); + + $this->field = FieldConfig::create([ + 'field_storage' => $this->fieldStorage, + 'bundle' => 'entity_test', + 'required' => TRUE, + ]); + $this->field->save(); + + $display_options = [ + 'type' => 'daterange_default', + 'label' => 'hidden', + 'settings' => [ + 'format_type' => 'fallback', + 'separator' => 'UNTRANSLATED', + ], + ]; + EntityViewDisplay::create([ + 'targetEntityType' => $this->field->getTargetEntityTypeId(), + 'bundle' => $this->field->getTargetBundle(), + 'mode' => 'default', + 'status' => TRUE, + ])->setComponent($this->fieldStorage->getName(), $display_options) + ->save(); + } + + /** + * Tests the field configured for date-only. + */ + public function testDateOnly() { + $this->fieldStorage->setSetting('datetime_type', DateRangeItem::DATETIME_TYPE_DATE); + $field_name = $this->fieldStorage->getName(); + // Create an entity. + $entity = EntityTest::create([ + 'name' => $this->randomString(), + $field_name => [ + 'value' => '2016-09-21', + 'end_value' => '2016-09-21', + ], + ]); + + // Dates are saved without a time value. When they are converted back into + // a \Drupal\datetime\DateTimeComputed object they should all have the same + // time. + $start_date = $entity->{$field_name}->start_date; + sleep(1); + $end_date = $entity->{$field_name}->end_date; + $this->assertEquals($start_date->getTimestamp(), $end_date->getTimestamp()); + } + +}