diff --git a/core/lib/Drupal/Core/Datetime/DrupalDateTime.php b/core/lib/Drupal/Core/Datetime/DrupalDateTime.php index 572a6e3..27156e1 100644 --- a/core/lib/Drupal/Core/Datetime/DrupalDateTime.php +++ b/core/lib/Drupal/Core/Datetime/DrupalDateTime.php @@ -132,4 +132,17 @@ public function format($format, $settings = []) { return $value; } + /** + * Sets the default time for an object built from date-only data. + * + * The default time for a date without time can be anything, so long as it is + * consistently applied. If we use noon, dates in most timezones will have the + * same value for in both the local timezone and UTC. + * + * @param \Drupal\Core\Datetime\DrupalDateTime $date + */ + public static function setDefaultDateTime(DrupalDateTime $date) { + $date->setTime(12, 0, 0); + } + } diff --git a/core/modules/datetime/datetime.module b/core/modules/datetime/datetime.module index bb10d13..12c0f98 100644 --- a/core/modules/datetime/datetime.module +++ b/core/modules/datetime/datetime.module @@ -5,6 +5,7 @@ * Field hooks to implement a simple datetime field. */ +use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Routing\RouteMatchInterface; /** @@ -50,7 +51,11 @@ function datetime_help($route_name, RouteMatchInterface $route_match) { * same value for in both the local timezone and UTC. * * @param $date + * + * @deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use + * \Drupal\Core\Datetime\DrupalDateTime::setDefaultDateTime() instead. */ function datetime_date_default_time($date) { - $date->setTime(12, 0, 0); + @trigger_error('datetime_date_default_time() is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Datetime\DrupalDateTime::setDefaultDateTime() instead.', E_USER_DEPRECATED); + DrupalDateTime::setDefaultDateTime($date); } diff --git a/core/modules/datetime/src/DateTimeComputed.php b/core/modules/datetime/src/DateTimeComputed.php index 9320baf..123d848 100644 --- a/core/modules/datetime/src/DateTimeComputed.php +++ b/core/modules/datetime/src/DateTimeComputed.php @@ -56,12 +56,10 @@ public function getValue($langcode = NULL) { // 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 \Drupal\Core\Datetime\DrupalDateTime::setDefaultDateTime() // @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); + DrupalDateTime::setDefaultDateTime($this->date); } } } diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php index 71b9467..e623f13 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php @@ -202,10 +202,6 @@ protected function getFormatSettings() { * A render array. */ protected function buildDate(DrupalDateTime $date) { - if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { - // A date without time will pick up the current time, use the default. - datetime_date_default_time($date); - } $this->setTimeZone($date); $build = [ @@ -230,11 +226,6 @@ protected function buildDate(DrupalDateTime $date) { * A render array. */ protected function buildDateWithIsoAttribute(DrupalDateTime $date) { - if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { - // A date without time will pick up the current time, use the default. - datetime_date_default_time($date); - } - // Create the ISO date in Universal Time. $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z'; diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php index 3fc3157..782e1b8 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php @@ -110,10 +110,6 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $date = $item->date; $output = []; if (!empty($item->date)) { - if ($this->getFieldSetting('datetime_type') == 'date') { - // A date without time will pick up the current time, use the default. - datetime_date_default_time($date); - } $output = $this->formatDate($date); } $elements[$delta] = $output; diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php index f965e21..9d1fdcc 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php @@ -35,13 +35,8 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $date = $items[$delta]->date; // The date was created and verified during field_load(), so it is safe to // use without further inspection. - if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { - // A date without time will pick up the current time, use the default - // time. - datetime_date_default_time($date); - } $date->setTimezone(new \DateTimeZone($element['value']['#date_timezone'])); - $element['value']['#default_value'] = $date; + $element['value']['#default_value'] = $this->createDefaultValue($date, $element['value']['#date_timezone']); } return $element; @@ -59,9 +54,6 @@ public function massageFormValues(array $values, array $form, FormStateInterface $date = $item['value']; switch ($this->getFieldSetting('datetime_type')) { case DateTimeItem::DATETIME_TYPE_DATE: - // If this is a date-only field, set it to the default time so the - // timezone conversion can be reversed. - datetime_date_default_time($date); $format = DATETIME_DATE_STORAGE_FORMAT; break; @@ -77,4 +69,28 @@ public function massageFormValues(array $values, array $form, FormStateInterface return $values; } + /** + * Creates a date object for use as a default value. + * + * This will take a default value, apply the proper timezone for display in + * a widget, and set the default time for date-only fields. + * + * @param \Drupal\Core\Datetime\DrupalDateTime $date + * The UTC default date. + * @param string $timezone + * The timezone to apply. + * + * @return \Drupal\Core\Datetime\DrupalDateTime + * A date object for use as a default value in a field widget. + */ + protected function createDefaultValue($date, $timezone) { + // The date was created and verified during field_load(), so it is safe to + // use without further inspection. + if ($this->getFieldSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) { + DrupalDateTime::setDefaultDateTime($date); + } + $date->setTimezone(new \DateTimeZone($timezone)); + return $date; + } + } diff --git a/core/modules/datetime/src/Tests/DateTestBase.php b/core/modules/datetime/src/Tests/DateTestBase.php index a234ae0..ac1579b 100644 --- a/core/modules/datetime/src/Tests/DateTestBase.php +++ b/core/modules/datetime/src/Tests/DateTestBase.php @@ -5,6 +5,7 @@ @trigger_error('\Drupal\datetime\Tests\DateTestBase is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use \Drupal\Tests\BrowserTestBase instead. See https://www.drupal.org/node/2780063.', E_USER_DEPRECATED); use Drupal\Component\Utility\Unicode; +use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; @@ -185,4 +186,20 @@ protected function setSiteTimezone($timezone) { ->save(); } + /** + * Massages test date values. + * + * If a date object is generated directly by a test, then it needs to be + * adjusted to behave like the computed date from the item. + * + * @param \Drupal\Core\Datetime\DrupalDateTime $date + * A date object directly generated by the test. + */ + protected function massageTestDate($date) { + if ($this->field->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) { + // Set the default time for date-only items. + DrupalDateTime::setDefaultDateTime($date); + } + } + } diff --git a/core/modules/datetime/tests/src/Functional/DateTestBase.php b/core/modules/datetime/tests/src/Functional/DateTestBase.php index 369e793..c233951 100644 --- a/core/modules/datetime/tests/src/Functional/DateTestBase.php +++ b/core/modules/datetime/tests/src/Functional/DateTestBase.php @@ -3,6 +3,7 @@ namespace Drupal\Tests\datetime\Functional; use Drupal\Component\Utility\Unicode; +use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\Entity\EntityViewDisplay; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; @@ -181,4 +182,20 @@ protected function setSiteTimezone($timezone) { ->save(); } + /** + * Massages test date values. + * + * If a date object is generated directly by a test, then it needs to be + * adjusted to behave like the computed date from the item. + * + * @param \Drupal\Core\Datetime\DrupalDateTime $date + * A date object directly generated by the test. + */ + protected function massageTestDate($date) { + if ($this->field->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) { + // Set the default time for date-only items. + DrupalDateTime::setDefaultDateTime($date); + } + } + } diff --git a/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php b/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php index ab03ff5..fcdf1fc 100644 --- a/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php +++ b/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php @@ -99,7 +99,7 @@ public function testDateField() { // Formats that display a time component for date-only fields will display // the default time, so that is applied before calculating the expected // value. - datetime_date_default_time($date); + $this->massageTestDate($date); foreach ($options as $setting => $values) { foreach ($values as $new_value) { // Update the entity display settings. diff --git a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php index 9884007..5545aa5 100644 --- a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php +++ b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php @@ -2,6 +2,7 @@ namespace Drupal\Tests\datetime\Kernel; +use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Field\FieldItemInterface; use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem; @@ -122,22 +123,34 @@ public function testDateOnly() { $this->assertEqual($entity->field_datetime->value, $value); $this->assertEqual($entity->field_datetime[0]->value, $value); $this->assertEquals(DATETIME_STORAGE_TIMEZONE, $entity->field_datetime->date->getTimeZone()->getName()); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); + DrupalDateTime::setDefaultDateTime($entity->field_datetime->date); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); // Verify changing the date value. $new_value = '2016-11-04'; $entity->field_datetime->value = $new_value; $this->assertEqual($entity->field_datetime->value, $new_value); $this->assertEquals(DATETIME_STORAGE_TIMEZONE, $entity->field_datetime->date->getTimeZone()->getName()); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); + DrupalDateTime::setDefaultDateTime($entity->field_datetime->date); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); // Read changed entity and assert changed values. $this->entityValidateAndSave($entity); $entity = EntityTest::load($id); $this->assertEqual($entity->field_datetime->value, $new_value); $this->assertEquals(DATETIME_STORAGE_TIMEZONE, $entity->field_datetime->date->getTimeZone()->getName()); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); + DrupalDateTime::setDefaultDateTime($entity->field_datetime->date); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); // Test the generateSampleValue() method. $entity = EntityTest::create(); $entity->field_datetime->generateSampleItems(); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); + DrupalDateTime::setDefaultDateTime($entity->field_datetime->date); + $this->assertEquals('12:00:00', $entity->field_datetime->date->format('H:i:s')); $this->entityValidateAndSave($entity); } diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php index e99374c..b9238e8 100644 --- a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php @@ -58,9 +58,6 @@ public function massageFormValues(array $values, array $form, FormStateInterface $start_date = $item['value']; switch ($this->getFieldSetting('datetime_type')) { case DateRangeItem::DATETIME_TYPE_DATE: - // If this is a date-only field, set it to the default time so the - // timezone conversion can be reversed. - datetime_date_default_time($start_date); $format = DATETIME_DATE_STORAGE_FORMAT; break; @@ -88,9 +85,6 @@ public function massageFormValues(array $values, array $form, FormStateInterface $end_date = $item['end_value']; switch ($this->getFieldSetting('datetime_type')) { case DateRangeItem::DATETIME_TYPE_DATE: - // If this is a date-only field, set it to the default time so the - // timezone conversion can be reversed. - datetime_date_default_time($end_date); $format = DATETIME_DATE_STORAGE_FORMAT; break; @@ -142,30 +136,4 @@ public function validateStartEnd(array &$element, FormStateInterface $form_state } } - /** - * Creates a date object for use as a default value. - * - * This will take a default value, apply the proper timezone for display in - * a widget, and set the default time for date-only fields. - * - * @param \Drupal\Core\Datetime\DrupalDateTime $date - * The UTC default date. - * @param string $timezone - * The timezone to apply. - * - * @return \Drupal\Core\Datetime\DrupalDateTime - * A date object for use as a default value in a field widget. - */ - protected function createDefaultValue($date, $timezone) { - // The date was created and verified during field_load(), so it is safe to - // use without further inspection. - if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { - // A date without time will pick up the current time, use the default - // time. - datetime_date_default_time($date); - } - $date->setTimezone(new \DateTimeZone($timezone)); - return $date; - } - } diff --git a/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php b/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php index 23ba8fa..ce6e22b 100644 --- a/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php +++ b/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php @@ -108,8 +108,8 @@ public function testDateRangeField() { // Formats that display a time component for date-only fields will display // the default time, so that is applied before calculating the expected // value. - datetime_date_default_time($start_date); - datetime_date_default_time($end_date); + $this->massageTestDate($start_date); + $this->massageTestDate($end_date); // Reset display options since these get changed below. $this->displayOptions = [ @@ -198,7 +198,7 @@ public function testDateRangeField() { $id = $match[1]; $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); - datetime_date_default_time($start_date); + $this->massageTestDate($start_date); $this->displayOptions = [ 'type' => 'daterange_default', diff --git a/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php b/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php index 67e1b9d..54f805f 100644 --- a/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php +++ b/core/modules/datetime_range/tests/src/Kernel/DateRangeItemTest.php @@ -100,6 +100,8 @@ public function testDateOnly() { sleep(1); $end_date = $entity->{$field_name}->end_date; $this->assertEquals($start_date->getTimestamp(), $end_date->getTimestamp()); + $this->assertEquals('12:00:00', $start_date->format('H:i:s')); + $this->assertEquals('12:00:00', $end_date->format('H:i:s')); } }