? sites/default/files ? sites/default/settings.php Index: CHANGELOG.txt =================================================================== RCS file: /cvs/drupal/drupal/CHANGELOG.txt,v retrieving revision 1.285 diff -u -p -r1.285 CHANGELOG.txt --- CHANGELOG.txt 2 Nov 2008 10:52:53 -0000 1.285 +++ CHANGELOG.txt 4 Nov 2008 19:18:57 -0000 @@ -37,6 +37,16 @@ Drupal 7.0, xxxx-xx-xx (development vers * Added support for language-aware searches. - Testing: * Added test framework and tests. +- Improved time zone support: + * Drupal now uses PHP's time zone database when rendering dates in local + time. Site-wide and user-configured time zone offsets have been converted + to time zone names, e.g. Africa/Abidjan. + * In some cases the upgrade and install scripts do not choose the preferred + site default time zone. The automatically-selected time zone can be + corrected at admin/settings/date-time. + * If your site is being upgraded from Drupal 6 and you do not have the + contributed date or event modules installed, user time zone settings will + have to be reconfigured by each user. - Removed ping module: * Contributed modules with similar functionality are available. - Refactored the "access rules" component of user module: Index: install.php =================================================================== RCS file: /cvs/drupal/drupal/install.php,v retrieving revision 1.138 diff -u -p -r1.138 install.php --- install.php 29 Oct 2008 10:08:51 -0000 1.138 +++ install.php 4 Nov 2008 19:18:57 -0000 @@ -727,6 +727,8 @@ function install_tasks($profile, $task) // Add JavaScript validation. _user_password_dynamic_validation(); drupal_add_js(drupal_get_path('module', 'system') . '/system.js', 'module'); + // Add JavaScript time zone detection. + drupal_add_js('misc/timezone.js'); // We add these strings as settings because JavaScript translation does not // work on install time. drupal_add_js(array('copyFieldValue' => array('edit-site-mail' => array('edit-account-mail')), 'cleanURL' => array('success' => st('Your server has been successfully tested to support this feature.'), 'failure' => st('Your system configuration does not currently support this feature. The handbook page on Clean URLs has additional troubleshooting information.'), 'testing' => st('Testing clean URLs...'))), 'setting'); @@ -735,7 +737,6 @@ function install_tasks($profile, $task) if (Drupal.jsEnabled) { $(document).ready(function() { Drupal.cleanURLsInstallCheck(); - Drupal.setDefaultTimezone(); }); }', 'inline'); // Build menu to allow clean URL check. @@ -1077,10 +1078,11 @@ function install_configure_form(&$form_s $form['server_settings']['date_default_timezone'] = array( '#type' => 'select', '#title' => st('Default time zone'), - '#default_value' => 0, + '#default_value' => date_default_timezone_get(), '#options' => _system_zonelist(), '#description' => st('By default, dates in this site will be displayed in the chosen time zone.'), '#weight' => 5, + '#attributes' => array('class' => 'timezone-detect'), ); $form['server_settings']['clean_url'] = array( Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.815 diff -u -p -r1.815 common.inc --- includes/common.inc 1 Nov 2008 21:21:34 -0000 1.815 +++ includes/common.inc 4 Nov 2008 19:18:58 -0000 @@ -1282,7 +1282,7 @@ function format_interval($timestamp, $gr * before a character to avoid interpreting the character as part of a date * format. * @param $timezone - * Time zone offset in seconds; if omitted, the user's time zone is used. + * Time zone identifier; if omitted, the user's time zone is used. * @param $langcode * Optional language code to translate to a language other than what is used * to display the page. @@ -1290,17 +1290,21 @@ function format_interval($timestamp, $gr * A translated date string in the requested format. */ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) { + static $timezones = array(); if (!isset($timezone)) { global $user; - if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) { + if (variable_get('configurable_timezones', 1) && $user->uid && $user->timezone) { $timezone = $user->timezone; } else { - $timezone = variable_get('date_default_timezone', 0); + $timezone = variable_get('date_default_timezone', 'UTC'); } } - - $timestamp += $timezone; + // Store DateTimeZone objects in an array rather than repeatedly + // contructing identical objects over the life of a request. + if (!isset($timezones[$timezone])) { + $timezones[$timezone] = timezone_open($timezone); + } switch ($type) { case 'small': @@ -1319,28 +1323,27 @@ function format_date($timestamp, $type = $max = strlen($format); $date = ''; + // Create a DateTime object from the timestamp. + $date_time = date_create('@' . $timestamp); + // Set the time zone for the DateTime object. + date_timezone_set($date_time, $timezones[$timezone]); + for ($i = 0; $i < $max; $i++) { $c = $format[$i]; - if (strpos('AaDlM', $c) !== FALSE) { - $date .= t(gmdate($c, $timestamp), array(), $langcode); + if (strpos('AaeDlMT', $c) !== FALSE) { + $date .= t(date_format($date_time, $c), array(), $langcode); } elseif ($c == 'F') { // Special treatment for long month names: May is both an abbreviation // and a full month name in English, but other languages have // different abbreviations. - $date .= trim(t('!long-month-name ' . gmdate($c, $timestamp), array('!long-month-name' => ''), $langcode)); + $date .= trim(t('!long-month-name ' . date_format($date_time, $c), array('!long-month-name' => ''), $langcode)); } - elseif (strpos('BdgGhHiIjLmnsStTUwWYyz', $c) !== FALSE) { - $date .= gmdate($c, $timestamp); + elseif (strpos('BcdGgHhIijLmNnOoPSstUuWwYyZz', $c) !== FALSE) { + $date .= date_format($date_time, $c); } elseif ($c == 'r') { - $date .= format_date($timestamp - $timezone, 'custom', 'D, d M Y H:i:s O', $timezone, $langcode); - } - elseif ($c == 'O') { - $date .= sprintf('%s%02d%02d', ($timezone < 0 ? '-' : '+'), abs($timezone / 3600), abs($timezone % 3600) / 60); - } - elseif ($c == 'Z') { - $date .= $timezone; + $date .= format_date($timestamp, 'custom', 'D, d M Y H:i:s O', $timezone, $langcode); } elseif ($c == '\\') { $date .= $format[++$i]; Index: misc/timezone.js =================================================================== RCS file: misc/timezone.js diff -N misc/timezone.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ misc/timezone.js 4 Nov 2008 19:18:58 -0000 @@ -0,0 +1,57 @@ +// $Id$ + +/** + * Set the client's system time zone as default values of form fields. + */ +Drupal.behaviors.setTimezone = { + attach: function(context) { + $('select.timezone-detect:not(.timezone-processed)', context).addClass('timezone-processed').each(function() { + var dateString = Date(); + // In some client environments, date strings include a time zone + // abbreviation, between 3 and 5 letters enclosed in parentheses, + // which can be interpreted by PHP. + var matches = dateString.match(/\(([A-Z]{3,5})\)/); + var abbreviation = matches ? matches[1] : 0; + + // For all other client environments, the abbreviation is set to "0" + // and the current offset from UTC and daylight saving time status are + // used to guess the time zone. + var dateNow = new Date(); + var offsetNow = dateNow.getTimezoneOffset() * -60; + + // Use January 1 and July 1 as test dates for determining daylight + // saving time status by comparing their offsets. + var dateJan = new Date(dateNow.getFullYear(), 0, 1, 12, 0, 0, 0); + var dateJul = new Date(dateNow.getFullYear(), 6, 1, 12, 0, 0, 0); + var offsetJan = dateJan.getTimezoneOffset() * -60; + var offsetJul = dateJul.getTimezoneOffset() * -60; + + var isDaylightSavingTime; + // If the offset from UTC is identical on January 1 and July 1, + // assume daylight saving time is not used in this time zone. + if (offsetJan == offsetJul) { + isDaylightSavingTime = ''; + } + // If the maximum annual offset is equivalent to the current offset, + // assume daylight saving time is in effect. + else if (Math.max(offsetJan, offsetJul) == offsetNow) { + isDaylightSavingTime = 1; + } + // Otherwise, assume daylight saving time is not in effect. + else { + isDaylightSavingTime = 0; + } + + // Submit request to the system/timezone callback and set the form field to + // the response time zone. The client date is passed to the callback for + // debugging purposes. + var path = 'system/timezone/' + abbreviation + '/' + offsetNow + '/' + isDaylightSavingTime; + var element = this; + $.getJSON(Drupal.settings.basePath, { q: path, date: dateString }, function(data) { + if (data) { + $(element).val(data); + } + }); + }); + } +}; Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.102 diff -u -p -r1.102 system.admin.inc --- modules/system/system.admin.inc 16 Oct 2008 20:23:08 -0000 1.102 +++ modules/system/system.admin.inc 4 Nov 2008 19:18:59 -0000 @@ -1567,19 +1567,11 @@ function system_date_time_settings() { $form['locale']['date_default_timezone'] = array( '#type' => 'select', '#title' => t('Default time zone'), - '#default_value' => variable_get('date_default_timezone', 0), + '#default_value' => variable_get('date_default_timezone', date_default_timezone_get()), '#options' => $zones, '#description' => t('Select the default site time zone.') ); - $form['locale']['configurable_timezones'] = array( - '#type' => 'radios', - '#title' => t('User-configurable time zones'), - '#default_value' => variable_get('configurable_timezones', 1), - '#options' => array(t('Disabled'), t('Enabled')), - '#description' => t('When enabled, users can set their own time zone and dates will be displayed accordingly.') - ); - $form['locale']['date_first_day'] = array( '#type' => 'select', '#title' => t('First day of week'), @@ -1588,6 +1580,42 @@ function system_date_time_settings() { '#description' => t('The first day of the week for calendar views.') ); + $form['timezone'] = array( + '#type' => 'fieldset', + '#title' => t('User time zones'), + ); + + $form['timezone']['configurable_timezones'] = array( + '#type' => 'radios', + '#title' => t('User-configurable time zones'), + '#default_value' => variable_get('configurable_timezones', 1), + '#options' => array(0 => t('Disabled'), 1 => t('Enabled')), + '#description' => t('When enabled, users can set their own time zone and dates will be displayed accordingly.') + ); + + $form['timezone']['user_default_timezone'] = array( + '#type' => 'radios', + '#title' => t('User time zone defaults'), + '#default_value' => variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT), + '#options' => array( + DRUPAL_USER_TIMEZONE_DEFAULT => t('New users will be set to the default time zone at registration.'), + DRUPAL_USER_TIMEZONE_EMPTY => t('New users will get an empty time zone at registration.'), + DRUPAL_USER_TIMEZONE_SELECT => t('New users will select their own time zone at registration.'), + ), + '#description' => t('Method for setting user time zones at registration when user-configurable time zones are enabled. This only affects the initial time zone setting for a new registration. Users will be able to change their time zone any time they edit their account.') + ); + + $form['timezone']['empty_timezone_message'] = array( + '#type' => 'radios', + '#title' => t('Empty user time zones'), + '#default_value' => variable_get('empty_timezone_message', DRUPAL_EMPTY_TIMEZONE_IGNORE), + '#options' => array( + DRUPAL_EMPTY_TIMEZONE_IGNORE => t('Ignore empty user time zones.'), + DRUPAL_EMPTY_TIMEZONE_REMIND => t('Remind users at login if their time zone is not set.'), + ), + '#description' => t('Handling for empty user time zones when user-configurable time zones are enabled. Use this option to help ensure that users set the correct time zone.') + ); + $form['date_formats'] = array( '#type' => 'fieldset', '#title' => t('Formatting'), Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.277 diff -u -p -r1.277 system.install --- modules/system/system.install 3 Nov 2008 06:33:21 -0000 1.277 +++ modules/system/system.install 4 Nov 2008 19:18:59 -0000 @@ -3101,7 +3101,47 @@ function system_update_7011() { } /** + * Convert default time zone offset to default time zone name. + */ +function system_update_7012() { + $ret = array(); + $timezone = NULL; + $timezones = _system_zonelist(); + // If the contributed Date module set a default time zone name, use this + // setting as the default time zone. + if ($timezone_name = variable_get('date_default_timezone_name', NULL) and isset($timezones[$timezone_name])) { + $timezone = $timezone_name; + } + // If the contributed Event module has set a default site time zone, look up + // the time zone name and use it as the default time zone. + if (!$timezone and $timezone_id = variable_get('date_default_timezone_id', 0)) { + try { + $timezone_name = db_result(db_query('SELECT name FROM {event_timezone} WHERE timezone = :timezone_id', array(':timezone_id' => $timezone_id))); + if ($timezone_name = str_replace(' ', '_', $timezone_name) and isset($timezones[$timezone_name])) { + $timezone = $timezone_name; + } + } + catch (PDOException $e) { + // Ignore error if event_timezone table does not exist or unexpected + // schema found. + } + } + // If the previous default time zone was a non-zero offset, guess the site's + // intended time zone based on that offset and the server's daylight saving + // time status. + if (!$timezone and $offset = variable_get('date_default_timezone', 0) and $timezone_name = timezone_name_from_abbr('', intval($offset), date('I')) and isset($timezones[$timezone_name])) { + $timezone = $timezone_name; + } + // Otherwise, the default time zone offset was zero, which is UTC. + if (!$timezone) { + $timezone = 'UTC'; + } + variable_set('date_default_timezone', $timezone); + drupal_set_message('The default time zone has been set to ' . check_plain($timezone) . '. Please check the ' . l('date and time configuration page', 'admin/settings/date-time') . ' to configure it correctly.', 'warning'); + return $ret; +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */ - Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.635 diff -u -p -r1.635 system.module --- modules/system/system.module 31 Oct 2008 02:18:22 -0000 1.635 +++ modules/system/system.module 4 Nov 2008 19:19:00 -0000 @@ -42,6 +42,31 @@ define('DRUPAL_MINIMUM_PGSQL', '8.1'); define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 21600); /** + * New users will be set to the default time zone at registration. + */ +define('DRUPAL_USER_TIMEZONE_DEFAULT', 0); + +/** + * New users will get an empty time zone at registration. + */ +define('DRUPAL_USER_TIMEZONE_EMPTY', 1); + +/** + * New users will select their own timezone at registration. + */ +define('DRUPAL_USER_TIMEZONE_SELECT', 2); + +/** + * Ignore empty user time zones. + */ +define('DRUPAL_EMPTY_TIMEZONE_IGNORE', 0); + +/** + * Remind users at login if their time zone is not set. + */ +define('DRUPAL_EMPTY_TIMEZONE_REMIND', 1); + +/** * Implementation of hook_help(). */ function system_help($path, $arg) { @@ -357,6 +382,12 @@ function system_menu() { 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); + $items['system/timezone'] = array( + 'title' => 'Time zone', + 'page callback' => 'system_timezone', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); $items['admin'] = array( 'title' => 'Administer', 'access arguments' => array('access administration pages'), @@ -592,7 +623,7 @@ function system_menu() { ); $items['admin/settings/date-time'] = array( 'title' => 'Date and time', - 'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.", + 'description' => "Settings for how Drupal displays date and time, as well as the system's default time zone.", 'page callback' => 'drupal_get_form', 'page arguments' => array('system_date_time_settings'), 'access arguments' => array('administer site configuration'), @@ -737,29 +768,68 @@ function system_preprocess_page(&$variab function system_user_form(&$edit, &$user, $category = NULL) { if ($category == 'account') { $form['theme_select'] = system_theme_select_form(t('Selecting a different theme will change the look and feel of the site.'), isset($edit['theme']) ? $edit['theme'] : NULL, 2); - if (variable_get('configurable_timezones', 1)) { - $zones = _system_zonelist(); + system_user_timezone($edit, $form); + } + return $form; + } +} + +/** + * Implementation of hook_user_register(). + */ +function system_user_register(&$edit, &$user, $category = NULL) { + if (variable_get('configurable_timezones', 1)) { + $form = array(); + if (variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) == DRUPAL_USER_TIMEZONE_SELECT) { + system_user_timezone($edit, $form); + } + else { $form['timezone'] = array( - '#type' => 'fieldset', - '#title' => t('Locale settings'), - '#weight' => 6, - '#collapsible' => TRUE, - ); - $form['timezone']['timezone'] = array( - '#type' => 'select', - '#title' => t('Time zone'), - '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0), - '#options' => $zones, - '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'), + '#type' => 'hidden', + '#value' => variable_get('user_default_timezone', DRUPAL_USER_TIMEZONE_DEFAULT) ? '' : variable_get('date_default_timezone', ''), ); } - return $form; } } /** + * Implementation of hook_user_login(). + */ +function system_user_login(&$edit, &$user, $category = NULL) { + // If the user has a NULL time zone, notify them to set a time zone. + if (!$user->timezone && variable_get('configurable_timezones', 1) && variable_get('empty_timezone_message', DRUPAL_EMPTY_TIMEZONE_IGNORE)) { + drupal_set_message(t('Please configure your account time zone setting.', array('@user-edit' => url("user/$user->uid/edit", array('query' => drupal_get_destination(), 'fragment' => 'edit-timezone'))))); + } +} + +/** + * Add the time zone field to the user edit and register forms. + */ +function system_user_timezone(&$edit, &$form) { + global $user; + $form['timezone'] = array( + '#type' => 'fieldset', + '#title' => t('Locale settings'), + '#weight' => 6, + '#collapsible' => TRUE, + ); + $form['timezone']['timezone'] = array( + '#type' => 'select', + '#title' => t('Time zone'), + '#default_value' => $edit['timezone'] ? $edit['timezone'] : ($edit['uid'] == $user->uid ? variable_get('date_default_timezone', '') : ''), + '#options' => _system_zonelist(($edit['uid'] != $user->uid)), + '#description' => t('Select the desired local time and time zone. Dates and times throughout this site will be displayed using this time zone.'), + ); + if (!$edit['timezone'] && $edit['uid'] == $user->uid) { + $form['timezone']['#description'] = t('Your time zone setting will be automatically detected if possible. Please confirm the selection and click save.'); + $form['timezone']['timezone']['#attributes'] = array('class' => 'timezone-detect'); + drupal_add_js('misc/timezone.js'); + } +} + +/** * Implementation of hook_block(). * * Generate a block with a promotional link to Drupal.org. @@ -2060,15 +2130,23 @@ function system_block_ip_action() { /** * Generate an array of time zones and their local time&date. + * + * @param $blank + * If evaluates true, prepend an empty time zone option to the array. */ -function _system_zonelist() { - $timestamp = REQUEST_TIME; - $zonelist = array(-11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2, -1, 0, 1, 2, 3, 3.5, 4, 5, 5.5, 5.75, 6, 6.5, 7, 8, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 14); - $zones = array(); - foreach ($zonelist as $offset) { - $zone = $offset * 3600; - $zones[$zone] = format_date($timestamp, 'custom', variable_get('date_format_long', 'l, F j, Y - H:i') . ' O', $zone); +function _system_zonelist($blank = NULL) { + $zonelist = timezone_identifiers_list(); + $zones = $blank ? array('' => t('- None selected -')) : array(); + foreach ($zonelist as $zone) { + // Because many time zones exist in PHP only for backward compatibility + // reasons and should not be used, the list is filtered by a regular + // expression. + if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) { + $zones[$zone] = t('@zone: @date', array('@zone' => t($zone), '@date' => format_date(REQUEST_TIME, 'custom', variable_get('date_format_long', 'l, F j, Y - H:i') . ' O', $zone))); + } } + // Sort the translated time zones alphabetically. + asort($zones); return $zones; } @@ -2099,6 +2177,21 @@ function system_check_http_request() { } /** + * Menu callback; Retrieve a JSON object containing a suggested time zone name. + */ +function system_timezone($abbreviation = '', $offset = -1, $is_daylight_saving_time = NULL) { + // An abbreviation of "0" passed in the callback arguments should be + // interpreted as the empty string. + $abbreviation = $abbreviation ? $abbreviation : ''; + $timezone = timezone_name_from_abbr($abbreviation, intval($offset), $is_daylight_saving_time); + // The client date is passed in for debugging purposes. + $date = isset($_GET['date']) ? $_GET['date'] : ''; + // @todo The following line is temporary debug logging and should be removed. + watchdog('timezone', 'Detected time zone: %timezone; client date: %date; abbreviation: %abbreviation; offset: %offset; daylight saving time: %is_daylight_saving_time.', array('%timezone' => $timezone, '%date' => $date, '%abbreviation' => $abbreviation, '%offset' => $offset, '%is_daylight_saving_time' => $is_daylight_saving_time), WATCHDOG_DEBUG); + drupal_json($timezone); +} + +/** * Format the Powered by Drupal text. * * @ingroup themeable Index: modules/system/system.test =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.test,v retrieving revision 1.23 diff -u -p -r1.23 system.test --- modules/system/system.test 1 Nov 2008 21:21:35 -0000 1.23 +++ modules/system/system.test 4 Nov 2008 19:19:00 -0000 @@ -469,6 +469,47 @@ class PageNotFoundTestCase extends Drupa } } +class DateTimeTestCase extends DrupalWebTestCase { + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('Date and time'), + 'description' => t('Configure date and time settings. Test date formatting and time zone handling, including daylight saving time.'), + 'group' => t('System'), + ); + } + + function testDateTime() { + // Setup date/time settings for Honolulu time. + variable_set('date_default_timezone', 'Pacific/Honolulu'); + variable_set('configurable_timezones', 0); + variable_set('date_format_medium', 'Y-m-d H:i:s O'); + + // Create some nodes with different authored-on dates. + $date1 = '2007-01-31 21:00:00 -1000'; + $date2 = '2007-07-31 21:00:00 -1000'; + $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article')); + $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article')); + + // Confirm date format and time zone. + $this->drupalGet("node/$node1->nid"); + $this->assertText('2007-01-31 21:00:00 -1000', t('Date should be identical, with GMT offset of -10 hours.')); + $this->drupalGet("node/$node2->nid"); + $this->assertText('2007-07-31 21:00:00 -1000', t('Date should be identical, with GMT offset of -10 hours.')); + + // Set time zone to Los Angeles time. + variable_set('date_default_timezone', 'America/Los_Angeles'); + + // Confirm date format and time zone. + $this->drupalGet("node/$node1->nid"); + $this->assertText('2007-01-31 23:00:00 -0800', t('Date should be two hours ahead, with GMT offset of -8 hours.')); + $this->drupalGet("node/$node2->nid"); + $this->assertText('2007-08-01 00:00:00 -0700', t('Date should be three hours ahead, with GMT offset of -7 hours.')); + } +} + class PageTitleFiltering extends DrupalWebTestCase { protected $content_user; protected $saved_title; @@ -532,4 +573,3 @@ class PageTitleFiltering extends DrupalW $this->assertText(check_plain($edit['title']), 'Check to make sure tags in the node title are converted.'); } } - Index: modules/user/user.install =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.install,v retrieving revision 1.13 diff -u -p -r1.13 user.install --- modules/user/user.install 20 Sep 2008 20:22:25 -0000 1.13 +++ modules/user/user.install 4 Nov 2008 19:19:00 -0000 @@ -158,9 +158,9 @@ function user_schema() { ), 'timezone' => array( 'type' => 'varchar', - 'length' => 8, + 'length' => 32, 'not null' => FALSE, - 'description' => t("User's timezone."), + 'description' => t("User's time zone."), ), 'language' => array( 'type' => 'varchar', @@ -292,6 +292,34 @@ function user_update_7001() { } /** + * Convert user time zones from time zone offsets to time zone names. + */ +function user_update_7002() { + $ret = array(); + db_change_field($ret, 'users', 'timezone', 'timezone', array('type' => 'varchar', 'length' => 32, 'not null' => FALSE, 'description' => t("User's time zone."))); + // If the contributed Date module has created a users.timezone_name + // column, use this data to set each user's time zone. + if (db_column_exists('users', 'timezone_name')) { + $ret[] = update_sql("UPDATE {users} SET timezone = timezone_name"); + } + // If the contributed Event module has stored user time zone information + // use that information to update the user accounts. + elseif (db_column_exists('users', 'timezone_id')) { + $results = db_query("SELECT DISTINCT u.timezone_id, t.name FROM {users} u LEFT JOIN {event_timezones} t on u.timezone_id = t.timezone"); + foreach ($results as $row) { + $name = str_replace(' ', '_', $row->name); + $ret[] = update_sql("UPDATE {users} SET timezone = '$name' WHERE timezone_id = " . $row->timezone_id); + } + } + else { + $ret[] = update_sql("UPDATE {users} SET timezone = NULL"); + variable_set('empty_timezone_message', 1); + drupal_set_message('User time zones have been emptied and need to be set to the correct values. Use the new ' . l('time zone options', 'admin/settings/date-time') . ' to choose whether to remind users at login to set the correct time zone.', 'warning'); + } + return $ret; +} + +/** * @} End of "defgroup user-updates-6.x-to-7.x" * The next series of updates should start at 8000. */ Index: modules/user/user.js =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.js,v retrieving revision 1.8 diff -u -p -r1.8 user.js --- modules/user/user.js 29 Oct 2008 10:01:28 -0000 1.8 +++ modules/user/user.js 4 Nov 2008 19:19:00 -0000 @@ -160,14 +160,6 @@ Drupal.evaluatePasswordStrength = functi }; /** - * Set the client's system timezone as default values of form fields. - */ -Drupal.setDefaultTimezone = function() { - var offset = new Date().getTimezoneOffset() * -60; - $("#edit-date-default-timezone, #edit-user-register-timezone").val(offset); -}; - -/** * On the admin/user/settings page, conditionally show all of the * picture-related form elements depending on the current value of the * "Picture support" radio buttons. Index: modules/user/user.module =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.module,v retrieving revision 1.930 diff -u -p -r1.930 user.module --- modules/user/user.module 26 Oct 2008 18:06:39 -0000 1.930 +++ modules/user/user.module 4 Nov 2008 19:19:01 -0000 @@ -2403,25 +2403,6 @@ function user_register() { $form = array_merge($form, $extra); } - if (variable_get('configurable_timezones', 1)) { - // Override field ID, so we only change timezone on user registration, - // and never touch it on user edit pages. - $form['timezone'] = array( - '#type' => 'hidden', - '#default_value' => variable_get('date_default_timezone', NULL), - '#id' => 'edit-user-register-timezone', - ); - - // Add the JavaScript callback to automatically set the timezone. - drupal_add_js(' -// Global Killswitch -if (Drupal.jsEnabled) { - $(document).ready(function() { - Drupal.setDefaultTimezone(); - }); -}', 'inline'); - } - $form['submit'] = array('#type' => 'submit', '#value' => t('Create new account'), '#weight' => 30); $form['#validate'][] = 'user_register_validate'; Index: modules/user/user.test =================================================================== RCS file: /cvs/drupal/drupal/modules/user/user.test,v retrieving revision 1.17 diff -u -p -r1.17 user.test --- modules/user/user.test 10 Oct 2008 07:49:49 -0000 1.17 +++ modules/user/user.test 4 Nov 2008 19:19:01 -0000 @@ -23,9 +23,9 @@ class UserRegistrationTestCase extends D // Set user registration to "Visitors can create accounts and no administrator approval is required." variable_set('user_register', 1); - // Enable user configurable timezone, and set the default timezone to +1 hour (or +3600 seconds). + // Enable user-configurable time zones, and set the default time zone to Brussels time. variable_set('configurable_timezones', 1); - variable_set('date_default_timezone', 3600); + variable_set('date_default_timezone', 'Europe/Brussels'); $edit = array(); $edit['name'] = $name = $this->randomName(); @@ -45,7 +45,7 @@ class UserRegistrationTestCase extends D $this->assertEqual($user->signature, '', t('Correct signature field.')); $this->assertTrue(($user->created > REQUEST_TIME - 20 ), t('Correct creation time.')); $this->assertEqual($user->status, variable_get('user_register', 1) == 1 ? 1 : 0, t('Correct status field.')); - $this->assertEqual($user->timezone, variable_get('date_default_timezone', NULL), t('Correct timezone field.')); + $this->assertEqual($user->timezone, variable_get('date_default_timezone', NULL), t('Correct time zone field.')); $this->assertEqual($user->language, '', t('Correct language field.')); $this->assertEqual($user->picture, '', t('Correct picture field.')); $this->assertEqual($user->init, $mail, t('Correct init field.')); @@ -524,6 +524,61 @@ class UserAdminTestCase extends DrupalWe } } +class UserTimeZoneTestCase extends DrupalWebTestCase { + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('User time zones'), + 'description' => t('Set a user time zone and verify that dates are displayed in local time.'), + 'group' => t('User'), + ); + } + + function testUserTimeZone() { + // Setup date/time settings for Los Angeles time. + variable_set('date_default_timezone', 'America/Los_Angeles'); + variable_set('configurable_timezones', 1); + variable_set('date_format_medium', 'Y-m-d H:i T'); + + // Create a user account and login. + $web_user = $this->drupalCreateUser(); + $this->drupalLogin($web_user); + + // Create some nodes with different authored-on dates. + $date1 = '2007-03-09 21:00:00 -0800'; + $date2 = '2007-03-11 01:00:00 -0800'; + $date3 = '2007-03-20 21:00:00 -0700'; + $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article')); + $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article')); + $node3 = $this->drupalCreateNode(array('created' => strtotime($date3), 'type' => 'article')); + + // Confirm date format and time zone. + $this->drupalGet("node/$node1->nid"); + $this->assertText('2007-03-09 21:00 PST', t('Date should be PST.')); + $this->drupalGet("node/$node2->nid"); + $this->assertText('2007-03-11 01:00 PST', t('Date should be PST.')); + $this->drupalGet("node/$node3->nid"); + $this->assertText('2007-03-20 21:00 PDT', t('Date should be PDT.')); + + // Change user time zone to Santiago time. + $edit = array(); + $edit['mail'] = $web_user->mail; + $edit['timezone'] = 'America/Santiago'; + $this->drupalPost("user/$web_user->uid/edit", $edit, t('Save')); + $this->assertText(t('The changes have been saved.'), t('Time zone changed to Santiago time.')); + + // Confirm date format and time zone. + $this->drupalGet("node/$node1->nid"); + $this->assertText('2007-03-10 02:00 CLST', t('Date should be Chile summer time; five hours ahead of PST.')); + $this->drupalGet("node/$node2->nid"); + $this->assertText('2007-03-11 05:00 CLT', t('Date should be Chile time; four hours ahead of PST')); + $this->drupalGet("node/$node3->nid"); + $this->assertText('2007-03-21 00:00 CLT', t('Date should be Chile time; three hours ahead of PDT.')); + } +} + /** * Test user autocompletion. */