? 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	3 Nov 2008 23:26:54 -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	3 Nov 2008 23:26:54 -0000
@@ -1077,7 +1077,7 @@ 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,
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	3 Nov 2008 23:26:55 -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) {
-  if (!isset($timezone)) {
+  static $timezones = array();
+  if (!$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: 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	3 Nov 2008 23:26:55 -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	3 Nov 2008 23:26:56 -0000
@@ -3033,7 +3033,6 @@ function system_update_7007() {
   return $ret;
 }
 
-
 /**
  * Use the poll_choice primary key to record votes in poll_votes rather than
  * the choice order. Rename chorder to weight.
@@ -3101,7 +3100,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 <em>' . check_plain($timezone) . '</em>. 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.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.js,v
retrieving revision 1.16
diff -u -p -r1.16 system.js
--- modules/system/system.js	29 Oct 2008 10:01:27 -0000	1.16
+++ modules/system/system.js	3 Nov 2008 23:26:56 -0000
@@ -117,3 +117,54 @@ Drupal.behaviors.dateTime = {
     $('select.date-format', context).trigger('change');
   }
 };
+
+/**
+ * Set the client's system time zone as default values of form fields.
+ */
+Drupal.setDefaultTimezone = 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.
+  var path = 'system/timezone/' + abbreviation + '/' + offsetNow + '/' + isDaylightSavingTime;
+  // The client date is passed to the callback for debugging purposes.
+  $.getJSON(Drupal.settings.basePath, { q: path, date: dateString }, function (data) {
+    if (data) {
+      $("#edit-date-default-timezone, #edit-timezone").val(data);
+    }
+  });
+};
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	3 Nov 2008 23:26:56 -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,72 @@ 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 <a href="@user-edit">account time zone setting</a>.', 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.');
+    drupal_add_js(drupal_get_path('module', 'system') . '/system.js');
+    drupal_add_js('if (Drupal.jsEnabled) {
+                     $(document).ready(function() {
+                       Drupal.setDefaultTimezone();
+                     });
+                   }', 'inline');
+  }
+}
+
+/**
  * Implementation of hook_block().
  *
  * Generate a block with a promotional link to Drupal.org.
@@ -2060,15 +2134,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 +2181,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'] : '';
+  // Log a debug message.
+  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	3 Nov 2008 23:26:56 -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', 'Date should be identical, with GMT offset of -10 hours.');
+    $this->drupalGet("node/$node2->nid");
+    $this->assertText('2007-07-31 21:00:00 -1000', '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', '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', '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	3 Nov 2008 23:26:56 -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	3 Nov 2008 23:26:56 -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	3 Nov 2008 23:26:57 -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	3 Nov 2008 23:26:57 -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', 'Date should be PST.');
+    $this->drupalGet("node/$node2->nid");
+    $this->assertText('2007-03-11 01:00 PST', 'Date should be PST.');
+    $this->drupalGet("node/$node3->nid");
+    $this->assertText('2007-03-20 21:00 PDT', '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', 'Date should be Chile summer time; five hours ahead of PST.');
+    $this->drupalGet("node/$node2->nid");
+    $this->assertText('2007-03-11 05:00 CLT', 'Date should be Chile time; four hours ahead of PST');
+    $this->drupalGet("node/$node3->nid");
+    $this->assertText('2007-03-21 00:00 CLT', 'Date should be Chile time; three hours ahead of PDT.');
+  }
+}
+
 /**
  * Test user autocompletion.
  */
