diff --git a/core/modules/datetime/config/schema/datetime.schema.yml b/core/modules/datetime/config/schema/datetime.schema.yml index a5c50b1..6ed9248 100644 --- a/core/modules/datetime/config/schema/datetime.schema.yml +++ b/core/modules/datetime/config/schema/datetime.schema.yml @@ -9,6 +9,9 @@ field.storage_settings.datetime: datetime_type: type: string label: 'Date type' + timezone_handling: + type: string + label: 'Timezone handling' field.field_settings.datetime: type: mapping @@ -95,6 +98,9 @@ field.storage_settings.daterange: daterange_type: type: string label: 'Date type' + timezone_handling: + type: string + label: 'Timezone handling' field.field_settings.daterange: type: mapping diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php index c45c24d..7ffc51c 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php @@ -49,8 +49,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) { datetime_date_default_time($end_date); } - $this->setTimeZone($start_date); - $this->setTimeZone($end_date); + $this->setTimeZone($start_date, $item->timezone); + $this->setTimeZone($end_date, $item->timezone); $start = $this->formatDate($start_date); $end = $this->formatDate($end_date); diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php index 1469bd4..7347a0e 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php @@ -53,8 +53,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $start_iso_date = $start_date->format("Y-m-d\TH:i:s") . 'Z'; $end_iso_date = $end_date->format("Y-m-d\TH:i:s") . 'Z'; - $this->setTimeZone($start_date); - $this->setTimeZone($end_date); + $this->setTimeZone($start_date, $item->timezone); + $this->setTimeZone($end_date, $item->timezone); // Display the dates using theme datetime. $elements[$delta] = [ diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeFormatterBase.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeFormatterBase.php index f34f179..2927b51 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeFormatterBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangeFormatterBase.php @@ -96,6 +96,7 @@ public static function create(ContainerInterface $container, array $configuratio public static function defaultSettings() { return [ 'separator' => '-', + 'timezone_display' => DateRangeItem::TIMEZONE_USER, 'timezone_override' => '', ] + parent::defaultSettings(); } @@ -113,13 +114,37 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#default_value' => $this->getSetting('separator'), ]; - $form['timezone_override'] = [ - '#type' => 'select', - '#title' => $this->t('Time zone override'), - '#description' => $this->t('The time zone selected here will always be used'), - '#options' => system_time_zones(TRUE), - '#default_value' => $this->getSetting('timezone_override'), - ]; + // Timezone display is only applicable to datetime items. + if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('daterange_type') === DateRangeItem::DATERANGE_TYPE_DATETIME) { + $form['timezone_display'] = array( + '#type' => 'select', + '#title' => $this->t('Timezone display'), + '#description' => $this->t('The timezone to use when displaying this date.'), + '#default_value' => $this->getSetting('timezone_display'), + '#options' => array( + DateRangeItem::TIMEZONE_USER => $this->t("The user's timezone"), + DateRangeItem::TIMEZONE_NONE => $this->t("Timezone override") + ), + ); + + // If this field is using per-date timezone storage, add that as an option. + if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('timezone_handling') === DateRangeItem::TIMEZONE_DATE) { + $form['timezone_display']['#options'][DateRangeItem::TIMEZONE_DATE] = $this->t("The date's timezone"); + } + + $form['timezone_override'] = array( + '#type' => 'select', + '#title' => $this->t('Time zone override'), + '#description' => $this->t('The time zone selected here will always be used'), + '#options' => system_time_zones(TRUE), + '#default_value' => $this->getSetting('timezone_override'), + '#states' => array( + 'visible' => array( + ':input[name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][timezone_display]"]' => ['value' => DateRangeItem::TIMEZONE_NONE], + ), + ) + ); + } return $form; } @@ -135,7 +160,11 @@ public function settingsSummary() { } if ($override = $this->getSetting('timezone_override')) { - $summary[] = $this->t('Time zone: @timezone', ['@timezone' => $override]); + $summary[] = $this->t('Time zone: @timezone', array('@timezone' => $override)); + } + else { + // @todo Make human-readable. + $summary[] = $this->t('Time zone display: @timezone', array('@timezone' => $this->getSetting('timezone_display'))); } return $summary; @@ -164,12 +193,12 @@ public function settingsSummary() { * @param \Drupal\Core\Datetime\DrupalDateTime $date * A DrupalDateTime object. */ - protected function setTimeZone(DrupalDateTime $date) { + protected function setTimeZone(DrupalDateTime $date, $timezone = NULL) { if ($this->getFieldSetting('daterange_type') === DateRangeItem::DATERANGE_TYPE_DATE) { // A date without time has no timezone conversion. $timezone = DATETIME_STORAGE_TIMEZONE; } - else { + elseif (empty($timezone)) { $timezone = drupal_get_user_timezone(); } $date->setTimeZone(timezone_open($timezone)); diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php index a2a1b13..bb76090 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php @@ -38,8 +38,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) { datetime_date_default_time($end_date); } - $this->setTimeZone($start_date); - $this->setTimeZone($end_date); + $this->setTimeZone($start_date, $item->timezone); + $this->setTimeZone($end_date, $item->timezone); $start = $this->formatDate($start_date); $end = $this->formatDate($end_date); diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php index c4abd2d..350d39e 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php @@ -44,10 +44,10 @@ public function viewElements(FieldItemListInterface $items, $langcode) { // A date without time will pick up the current time, use the default. datetime_date_default_time($date); } - $this->setTimeZone($date); + $this->setTimeZone($date, $item->timezone); $output = $this->formatDate($date); - } + } $elements[$delta] = [ '#markup' => $output, '#cache' => [ diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php index 03c92ae..b330179 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php @@ -50,7 +50,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { // Create the ISO date in Universal Time. $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z'; - $this->setTimeZone($date); + $this->setTimeZone($date, $item->timezone); $output = $this->formatDate($date); } diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php index be9df38..2c3c041 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php @@ -83,6 +83,7 @@ public static function create(ContainerInterface $container, array $configuratio */ public static function defaultSettings() { return array( + 'timezone_display' => DateTimeItem::TIMEZONE_USER, 'timezone_override' => '', ) + parent::defaultSettings(); } @@ -93,13 +94,37 @@ public static function defaultSettings() { public function settingsForm(array $form, FormStateInterface $form_state) { $form = parent::settingsForm($form, $form_state); - $form['timezone_override'] = array( - '#type' => 'select', - '#title' => $this->t('Time zone override'), - '#description' => $this->t('The time zone selected here will always be used'), - '#options' => system_time_zones(TRUE), - '#default_value' => $this->getSetting('timezone_override'), - ); + // Timezone display is only applicable to datetime items. + if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATETIME) { + $form['timezone_display'] = array( + '#type' => 'select', + '#title' => $this->t('Timezone display'), + '#description' => $this->t('The timezone to use when displaying this date.'), + '#default_value' => $this->getSetting('timezone_display'), + '#options' => array( + DateTimeItem::TIMEZONE_USER => $this->t("The user's timezone"), + DateTimeItem::TIMEZONE_NONE => $this->t("Timezone override") + ), + ); + + // If this field is using per-date timezone storage, add that as an option. + if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('timezone_handling') === DateTimeItem::TIMEZONE_DATE) { + $form['timezone_display']['#options'][DateTimeItem::TIMEZONE_DATE] = $this->t("The date's timezone"); + } + + $form['timezone_override'] = array( + '#type' => 'select', + '#title' => $this->t('Time zone override'), + '#description' => $this->t('The time zone selected here will always be used'), + '#options' => system_time_zones(TRUE), + '#default_value' => $this->getSetting('timezone_override'), + '#states' => array( + 'visible' => array( + ':input[name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][timezone_display]"]' => ['value' => DateTimeItem::TIMEZONE_NONE], + ), + ) + ); + } return $form; } @@ -110,8 +135,15 @@ public function settingsForm(array $form, FormStateInterface $form_state) { public function settingsSummary() { $summary = parent::settingsSummary(); - if ($override = $this->getSetting('timezone_override')) { - $summary[] = $this->t('Time zone: @timezone', array('@timezone' => $override)); + if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATETIME) { + if ($override = $this->getSetting('timezone_override')) { + $summary[] = $this->t('Time zone: @timezone', array('@timezone' => $override)); + } + else { + // @todo Make human-readable. + $summary[] = $this->t('Time zone display: @timezone', array('@timezone' => $this->getSetting('timezone_display'))); + + } } return $summary; @@ -139,13 +171,15 @@ public function settingsSummary() { * * @param \Drupal\Core\Datetime\DrupalDateTime $date * A DrupalDateTime object. + * @param string $timezone + * (optional) A timezone to explicitly set the date to. */ - protected function setTimeZone(DrupalDateTime $date) { + protected function setTimeZone(DrupalDateTime $date, $timezone = NULL) { if ($this->getFieldSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) { // A date without time has no timezone conversion. $timezone = DATETIME_STORAGE_TIMEZONE; } - else { + elseif (empty($timezone)) { $timezone = drupal_get_user_timezone(); } $date->setTimeZone(timezone_open($timezone)); diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php index a74810a..7260945 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php @@ -34,7 +34,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { // A date without time will pick up the current time, use the default. datetime_date_default_time($date); } - $this->setTimeZone($date); + $this->setTimeZone($date, $item->timezone); $output = $this->formatDate($date); } diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateRangeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateRangeItem.php index 78e2cb8..720f73d 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldType/DateRangeItem.php +++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateRangeItem.php @@ -28,6 +28,7 @@ class DateRangeItem extends FieldItemBase { public static function defaultStorageSettings() { return [ 'daterange_type' => 'datetime', + 'timezone_handling' => static::TIMEZONE_USER, ] + parent::defaultStorageSettings(); } @@ -47,6 +48,28 @@ public static function defaultStorageSettings() { const DATERANGE_TYPE_ALLDAY = 'allday'; /** + * Timezone uses the site's timezone, regardless of the user's timezone. + */ + const TIMEZONE_SITE = 'site'; + + /** + * Timezone uses the user's timezone. + * + * @see drupal_get_user_timezone() + */ + const TIMEZONE_USER = 'user'; + + /** + * Timezone is set per-date. + */ + const TIMEZONE_DATE = 'date'; + + /** + * No timezone conversion is performed. + */ + const TIMEZONE_NONE = 'none'; + + /** * {@inheritdoc} */ public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { @@ -72,6 +95,9 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel ->setClass('\Drupal\datetime\DateTimeComputed') ->setSetting('date source', 'value2'); + $properties['timezone'] = DataDefinition::create('string') + ->setLabel(t('Timezone')); + return $properties; } @@ -91,10 +117,16 @@ public static function schema(FieldStorageDefinitionInterface $field_definition) 'type' => 'varchar', 'length' => 20, ], + 'timezone' => [ + 'description' => 'The date timezone', + 'type' => 'varchar', + 'length' => 50, + ], ], 'indexes' => [ 'value' => ['value'], 'value2' => ['value2'], + 'timezone' => ['timezone'], ], ]; } @@ -118,6 +150,29 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state '#disabled' => $has_data, ]; + $element['timezone_handling'] = array( + '#type' => 'select', + '#title' => t('Timezone handling'), + '#options' => array( + static::TIMEZONE_SITE => t("Site's timezone"), + static::TIMEZONE_DATE => t("Date's timezone"), + static::TIMEZONE_USER => t("User's timezone"), + static::TIMEZONE_NONE => t('No timezone conversion'), + ), + '#default_value' => $this->getSetting('timezone_handling'), + '#required' => TRUE, + '#states' => array( + // Hide the field if this is a date-only field. + 'visible' => array( + ':input[name="settings[datetime_type]"]' => ['value' => static::DATERANGE_TYPE_DATETIME], + ), + 'disabled' => array( + ':input[name="settings[datetime_type]"]' => ['value' => static::DATERANGE_TYPE_DATE], + ), + ), + '#disabled' => $has_data, + ); + return $element; } diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php index f07d564..1727fd3 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php +++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php @@ -28,6 +28,7 @@ class DateTimeItem extends FieldItemBase { public static function defaultStorageSettings() { return array( 'datetime_type' => 'datetime', + 'timezone_handling' => static::TIMEZONE_USER, ) + parent::defaultStorageSettings(); } @@ -42,6 +43,28 @@ public static function defaultStorageSettings() { const DATETIME_TYPE_DATETIME = 'datetime'; /** + * Timezone uses the site's timezone, regardless of the user's timezone. + */ + const TIMEZONE_SITE = 'site'; + + /** + * Timezone uses the user's timezone. + * + * @see drupal_get_user_timezone() + */ + const TIMEZONE_USER = 'user'; + + /** + * Timezone is set per-date. + */ + const TIMEZONE_DATE = 'date'; + + /** + * No timezone conversion is performed. + */ + const TIMEZONE_NONE = 'none'; + + /** * {@inheritdoc} */ public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { @@ -56,6 +79,9 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel ->setClass('\Drupal\datetime\DateTimeComputed') ->setSetting('date source', 'value'); + $properties['timezone'] = DataDefinition::create('string') + ->setLabel(t('Timezone')); + return $properties; } @@ -63,18 +89,25 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel * {@inheritdoc} */ public static function schema(FieldStorageDefinitionInterface $field_definition) { - return array( + $schema = array( 'columns' => array( 'value' => array( 'description' => 'The date value.', 'type' => 'varchar', 'length' => 20, ), + 'timezone' => array( + 'description' => 'The date timezone', + 'type' => 'varchar', + 'length' => 50, + ), ), 'indexes' => array( - 'value' => array('value'), + 'value' => array('value', 'timezone'), ), ); + + return $schema; } /** @@ -95,6 +128,29 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state '#disabled' => $has_data, ); + $element['timezone_handling'] = array( + '#type' => 'select', + '#title' => t('Timezone handling'), + '#options' => array( + static::TIMEZONE_SITE => t("Site's timezone"), + static::TIMEZONE_DATE => t("Date's timezone"), + static::TIMEZONE_USER => t("User's timezone"), + static::TIMEZONE_NONE => t('No timezone conversion'), + ), + '#default_value' => $this->getSetting('timezone_handling'), + '#required' => TRUE, + '#states' => array( + // Hide the field if this is a date-only field. + 'visible' => array( + ':input[name="settings[datetime_type]"]' => ['value' => static::DATETIME_TYPE_DATETIME], + ), + 'disabled' => array( + ':input[name="settings[datetime_type]"]' => ['value' => static::DATETIME_TYPE_DATE], + ), + ), + '#disabled' => $has_data, + ); + return $element; } diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php index f92955c..74f14ae 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php +++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php @@ -37,6 +37,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element = parent::formElement($items, $delta, $element, $form, $form_state); $date_order = $this->getSetting('date_order'); + $timezone = $items[$delta]->timezone ?: drupal_get_user_timezone(); if ($this->getFieldSetting('daterange_type') == DateRangeItem::DATERANGE_TYPE_DATETIME) { $time_type = $this->getSetting('time_type'); @@ -79,14 +80,25 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#type' => 'datelist', '#date_increment' => $increment, '#date_part_order' => $date_part_order, + '#date_timezone' => $timezone, ] + $element['value']; $element['value2'] = [ '#type' => 'datelist', '#date_increment' => $increment, '#date_part_order' => $date_part_order, + '#date_timezone' => $timezone, ] + $element['value2']; + if ($this->getFieldSetting('timezone_handling') === DateTimeItem::TIMEZONE_DATE) { + $element['timezone'] = array( + '#type' => 'select', + '#options' => array_combine(\DateTimeZone::listIdentifiers(), \DateTimeZone::listIdentifiers()), + // Default to user's timezone. + '#default_value' => $timezone, + ); + } + return $element; } diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php index 24af1ce..42fa1ac 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php +++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeDefaultWidget.php @@ -58,6 +58,7 @@ public static function create(ContainerInterface $container, array $configuratio */ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { $element = parent::formElement($items, $delta, $element, $form, $form_state); + $timezone = $items[$delta]->timezone ?: drupal_get_user_timezone(); // Identify the type of date and time elements to use. switch ($this->getFieldSetting('daterange_type')) { @@ -90,6 +91,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#date_time_format' => $time_format, '#date_time_element' => $time_type, '#date_time_callbacks' => array(), + '#date_timezone' => $timezone, ); $element['value2'] += array( @@ -99,8 +101,18 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#date_time_format' => $time_format, '#date_time_element' => $time_type, '#date_time_callbacks' => array(), + '#date_timezone' => $timezone, ); + if ($this->getFieldSetting('timezone_handling') === DateRangeItem::TIMEZONE_DATE) { + $element['timezone'] = array( + '#type' => 'select', + '#options' => array_combine(\DateTimeZone::listIdentifiers(), \DateTimeZone::listIdentifiers()), + // Default to user's timezone. + '#default_value' => $timezone, + ); + } + return $element; } diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php index 9c62f82..787f2be 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateRangeWidgetBase.php @@ -26,13 +26,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element['#theme_wrappers'][] = 'datetime_wrapper'; $element['#attributes']['class'][] = 'container-inline'; $element['#element_validate'][] = [$this, 'validateStartEnd']; + $timezone = $items[$delta]->timezone ?: drupal_get_user_timezone(); $element['value'] = array( '#title' => $this->t('Start'), '#type' => 'datetime', '#default_value' => NULL, '#date_increment' => 1, - '#date_timezone' => drupal_get_user_timezone(), + '#date_timezone' => $timezone, '#required' => $element['#required'], ); @@ -41,7 +42,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#type' => 'datetime', '#default_value' => NULL, '#date_increment' => 1, - '#date_timezone' => drupal_get_user_timezone(), + '#date_timezone' => $timezone, '#required' => $element['#required'], ); diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php index aa6175a..31e868e 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php @@ -30,7 +30,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen '#type' => 'datetime', '#default_value' => NULL, '#date_increment' => 1, - '#date_timezone' => drupal_get_user_timezone(), + '#date_timezone' => $items[$delta]->timezone ?: drupal_get_user_timezone(), '#required' => $element['#required'], ); @@ -40,7 +40,17 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element['value']['#date_timezone'] = DATETIME_STORAGE_TIMEZONE; } + if ($this->getFieldSetting('timezone_handling') === DateTimeItem::TIMEZONE_DATE) { + $element['timezone'] = array( + '#type' => 'select', + '#options' => array_combine(\DateTimeZone::listIdentifiers(), \DateTimeZone::listIdentifiers()), + // Default to user's timezone. + '#default_value' => $items[$delta]->timezone ?: drupal_get_user_timezone(), + ); + } + if ($items[$delta]->date) { + /** @var \Drupal\Core\Datetime\DrupalDateTime $date */ $date = $items[$delta]->date; // The date was created and verified during field_load(), so it is safe to // use without further inspection. @@ -51,6 +61,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen } $date->setTimezone(new \DateTimeZone($element['value']['#date_timezone'])); $element['value']['#default_value'] = $date; + $element['timezone']['#default_value'] = $date->format('e'); } return $element; diff --git a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php index d26434b..e452e6c 100644 --- a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php +++ b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php @@ -31,7 +31,10 @@ protected function setUp() { 'field_name' => 'field_datetime', 'type' => 'datetime', 'entity_type' => 'entity_test', - 'settings' => array('datetime_type' => 'date'), + 'settings' => array( + 'datetime_type' => 'date', + 'timezone_handling' => 'site', + ), )); $field_storage->save(); $field = FieldConfig::create([ @@ -120,4 +123,28 @@ public function testSetValueProperty() { $this->assertEqual($entity->field_datetime[0]->value, $value, '"Value" property can be set directly.'); } + /** + * Tests DateTimeItem with per-date timezone handling. + */ + public function testTimezoneDate() { + /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */ + $field_storage = FieldStorageConfig::load('entity_test.field_datetime'); + $field_storage->setSetting('timezone_handling', 'date'); + $field_storage->save(); + + // Use a non-UTC timezone. + $timezone = 'America/Yellowknife'; + + $entity = EntityTest::create(); + $value = '2014-01-01T20:00:00Z'; + + $entity->set('field_datetime', ['value' => $value, 'timezone' => $timezone]); + $entity->save(); + + // Load the entity. + $id = $entity->id(); + $entity = EntityTest::load($id); + $this->assertEqual($timezone, $entity->field_datetime[0]->timezone, '"timezone" property can be set.'); + } + }