diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php index a24f5dd..f73f083 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/TimestampFormatter.php @@ -132,7 +132,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) { $elements['timezone'] = [ '#type' => 'select', '#title' => $this->t('Time zone'), - '#options' => ['' => $this->t('- Default site/user time zone -')] + system_time_zones(FALSE), + '#options' => ['' => $this->t('- Default site/user time zone -')] + system_time_zones(FALSE, TRUE), '#default_value' => $this->getSetting('timezone'), ]; diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php index c28b7f8..540da55 100644 --- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php +++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php @@ -204,7 +204,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#title' => $this->t('Default time zone'), // Use system timezone if set, but avoid throwing a warning in PHP >=5.4 '#default_value' => @date_default_timezone_get(), - '#options' => system_time_zones(), + '#options' => system_time_zones(NULL, TRUE), '#description' => $this->t('By default, dates in this site will be displayed in the chosen time zone.'), '#weight' => 5, '#attributes' => ['class' => ['timezone-detect']], diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php index 71b9467..6dbc6ca 100644 --- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php +++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php @@ -98,7 +98,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#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), + '#options' => system_time_zones(TRUE, TRUE), '#default_value' => $this->getSetting('timezone_override'), ]; diff --git a/core/modules/system/src/Form/RegionalForm.php b/core/modules/system/src/Form/RegionalForm.php index c365fc0..a66b26b 100644 --- a/core/modules/system/src/Form/RegionalForm.php +++ b/core/modules/system/src/Form/RegionalForm.php @@ -65,7 +65,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { $system_date = $this->config('system.date'); // Date settings: - $zones = system_time_zones(); + $zones = system_time_zones(NULL, TRUE); $form['locale'] = [ '#type' => 'details', diff --git a/core/modules/system/system.module b/core/modules/system/system.module index a1a6b71..d327d4e 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -845,7 +845,7 @@ function system_user_timezone(&$form, FormStateInterface $form_state) { '#type' => 'select', '#title' => t('Time zone'), '#default_value' => $account->getTimezone() ? $account->getTimezone() : \Drupal::config('system.date')->get('timezone.default'), - '#options' => system_time_zones($account->id() != $user->id()), + '#options' => system_time_zones($account->id() != $user->id(), TRUE), '#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'), ]; $user_input = $form_state->getUserInput(); @@ -1355,10 +1355,15 @@ function system_mail($key, &$message, $params) { /** * Generate an array of time zones and their local time&date. * - * @param $blank + * @param mixed $blank * If evaluates true, prepend an empty time zone option to the array. + * @param bool $grouped + * (optional) Whether the timezones should be grouped by region. + * + * @return array + * An array or nested array containing time zones, keyed by the system name. */ -function system_time_zones($blank = NULL) { +function system_time_zones($blank = NULL, $grouped = FALSE) { $zonelist = timezone_identifiers_list(); $zones = $blank ? ['' => t('- None selected -')] : []; foreach ($zonelist as $zone) { @@ -1371,6 +1376,27 @@ function system_time_zones($blank = NULL) { } // Sort the translated time zones alphabetically. asort($zones); + if ($grouped) { + $grouped_zones = []; + foreach ($zones as $key => $value) { + $split = explode('/', $value); + $city = array_pop($split); + $region = array_shift($split); + if (!empty($region)) { + $grouped_zones[$region][$key] = empty($split) ? $city : $city . ' (' . join('/', $split) . ')'; + } + else { + $grouped_zones[$key] = $value; + } + } + foreach ($grouped_zones as $key => $value) { + if (is_array($grouped_zones[$key])) { + asort($grouped_zones[$key]); + } + } + $zones = $grouped_zones; + } + return $zones; } diff --git a/core/modules/system/tests/src/Kernel/Timezone/TimezoneTest.php b/core/modules/system/tests/src/Kernel/Timezone/TimezoneTest.php new file mode 100644 index 0000000..1daa00e --- /dev/null +++ b/core/modules/system/tests/src/Kernel/Timezone/TimezoneTest.php @@ -0,0 +1,64 @@ +assertInternalType('array', $result); + $this->assertArrayHasKey('Africa/Dar_es_Salaam', $result); + $this->assertEquals('Africa/Dar es Salaam', $result['Africa/Dar_es_Salaam']); + + // Tests time zone grouping. + $result = system_time_zones(NULL, TRUE); + + // Check a two-level time zone. + $this->assertInternalType('array', $result); + $this->assertArrayHasKey('Africa', $result); + $this->assertArrayHasKey('Africa/Dar_es_Salaam', $result['Africa']); + $this->assertEquals('Dar es Salaam', $result['Africa']['Africa/Dar_es_Salaam']); + + // Check a three level time zone. + $this->assertArrayHasKey('America', $result); + $this->assertArrayHasKey('America/Indiana/Indianapolis', $result['America']); + $this->assertEquals('Indianapolis (Indiana)', $result['America']['America/Indiana/Indianapolis']); + + // Make sure grouping hasn't erroneously created an entry with just the + // first and second levels. + $this->assertArrayNotHasKey('America/Indiana', $result['America']); + + // Make sure grouping hasn't duplicated an entry with just the first and + // third levels. + $this->assertArrayNotHasKey('America/Indianapolis', $result['America']); + + // Make sure that a grouped item isn't duplicated at the top level of the + // results array. + $this->assertArrayNotHasKey('America/Indiana/Indianapolis', $result); + + // Test that the ungrouped and grouped results have the same number of + // items. + $ungrouped_count = count(system_time_zones()); + $grouped_result = system_time_zones(NULL, TRUE); + $grouped_count = 0; + array_walk_recursive($grouped_result, function ($grouped_count) use + (&$grouped_count) { + $grouped_count++; + }); + $this->assertEquals($ungrouped_count, $grouped_count); + } + +} diff --git a/core/modules/views/src/Plugin/views/field/Date.php b/core/modules/views/src/Plugin/views/field/Date.php index 37455cc..3014c2f 100644 --- a/core/modules/views/src/Plugin/views/field/Date.php +++ b/core/modules/views/src/Plugin/views/field/Date.php @@ -119,7 +119,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { '#type' => 'select', '#title' => $this->t('Timezone'), '#description' => $this->t('Timezone to be used for date output.'), - '#options' => ['' => $this->t('- Default site/user timezone -')] + system_time_zones(FALSE), + '#options' => ['' => $this->t('- Default site/user timezone -')] + system_time_zones(FALSE, TRUE), '#default_value' => $this->options['timezone'], ]; foreach (array_merge(['custom'], array_keys($date_formats)) as $timezone_date_formats) {