? files
? sites/default/settings.php
Index: install.php
===================================================================
RCS file: /cvs/drupal/drupal/install.php,v
retrieving revision 1.62
diff -u -r1.62 install.php
--- install.php	25 Jun 2007 12:44:11 -0000	1.62
+++ install.php	28 Jun 2007 21:41:25 -0000
@@ -888,22 +888,39 @@
     '#weight' => 0,
   );
 
-  $zones = _system_zonelist();
-
   $form['server_settings'] = array(
     '#type' => 'fieldset',
     '#title' => st('Server settings'),
     '#collapsible' => FALSE,
   );
-  $form['server_settings']['date_default_timezone'] = array(
-    '#type' => 'select',
-    '#title' => st('Default time zone'),
-    '#default_value' => variable_get('date_default_timezone', 0),
-    '#options' => $zones,
-    '#description' => st('By default, dates in this site will be displayed in the chosen time zone.'),
-    '#weight' => 5,
-  );
-
+  if (date_handle_timezones()) {
+    $form['server_settings']['date_default_offset'] = array(
+      '#type' => 'hidden',
+      '#value' => variable_get('date_default_offset', NULL),
+    );
+    $form['server_settings']['date_default_timezone'] = array(
+      '#type' => 'select',
+      '#title' => t('Default time zone'),
+      '#default_value' => variable_get('date_default_timezone', NULL),
+      '#options' => date_zone_names(),
+      '#description' => st('By default, dates in this site will be displayed in the chosen time zone.'),
+      '#weight' => 5,
+      '#submit' => array('system_timezone_update_site' => array('date_default_timezone')),
+    );
+  }
+  else {
+    $form['server_settings']['date_default_timezone'] = array(
+      '#type' => 'hidden',
+      '#value' => variable_get('date_default_timezone', NULL),
+    );
+    $form['server_settings']['date_default_offset'] = array(
+      '#type' => 'select',
+      '#title' => t('Default time zone'),
+      '#default_value' => variable_get('date_default_offset', NULL),
+      '#options' => date_zone_offsets(),
+      '#description' => st('By default, dates in this site will be displayed in the chosen time zone.'),
+    );
+  }
   drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
   // We add these strings as settings because JavaScript translation does not
   // work on install time.
@@ -958,7 +975,9 @@
 
   variable_set('site_name', $form_state['values']['site_name']);
   variable_set('site_mail', $form_state['values']['site_mail']);
+  variable_set('date_default_offset', $form_state['values']['date_default_offset']);
   variable_set('date_default_timezone', $form_state['values']['date_default_timezone']);
+  date_update_sitezone($form, $form_state);
 
   // Turn this off temporarily so that we can pass a password through.
   variable_set('user_email_verification', FALSE);
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.666
diff -u -r1.666 common.inc
--- includes/common.inc	28 Jun 2007 07:48:40 -0000	1.666
+++ includes/common.inc	28 Jun 2007 18:54:50 -0000
@@ -1090,7 +1090,7 @@
       $timezone = $user->timezone;
     }
     else {
-      $timezone = variable_get('date_default_timezone', 0);
+      $timezone = variable_get('date_default_offset', NULL);
     }
   }
 
@@ -1137,7 +1137,6 @@
       $date .= $c;
     }
   }
-
   return $date;
 }
 
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.124
diff -u -r1.124 system.install
--- modules/system/system.install	26 Jun 2007 20:24:19 -0000	1.124
+++ modules/system/system.install	28 Jun 2007 18:53:05 -0000
@@ -3421,6 +3421,19 @@
 }
 
 /**
+ * Rename user->timezone to user->offset and add new user->timezone to hold timezone names.
+ * Alter variables to match new schema.
+ */
+function system_update_6025() {
+  $ret = array();
+  db_change_field($ret, 'users', 'timezone', 'offset', array('type' => 'varchar', 'length' => 8, 'not null' => FALSE, 'default' => NULL));
+  db_add_field($ret, 'users', 'timezone', array('type' => 'varchar', 'length' => 50, 'not null' => FALSE, 'default' => NULL));
+  variable_set('date_default_offset', variable_get('date_default_timezone', NULL));
+  variable_set('date_default_timezone', NULL);
+  return $ret;
+}
+
+/**
  * @} End of "defgroup updates-5.x-to-6.x"
  * The next series of updates should start at 7000.
  */
Index: modules/system/system.js
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.js,v
retrieving revision 1.8
diff -u -r1.8 system.js
--- modules/system/system.js	8 Jun 2007 12:51:59 -0000	1.8
+++ modules/system/system.js	28 Jun 2007 19:50:46 -0000
@@ -54,7 +54,7 @@
 
 Drupal.installDefaultTimezone = function() {
   var offset = new Date().getTimezoneOffset() * -60;
-  $("#edit-date-default-timezone").val(offset);
+  $("#edit-date-default-offset").val(offset);
 };
 
 /**
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.499
diff -u -r1.499 system.module
--- modules/system/system.module	28 Jun 2007 00:48:26 -0000	1.499
+++ modules/system/system.module	28 Jun 2007 22:05:21 -0000
@@ -373,24 +373,45 @@
     $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();
+      $zones = date_zone_offsets();
       $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.'),
-      );
+      if (date_handle_timezones()) {
+        $form['timezone']['offset'] = array(
+          '#type' => 'hidden',
+          '#value' => strlen($edit['offset']) ? $edit['offset'] : variable_get('date_default_offset', NULL),
+        );
+        $form['timezone']['timezone'] = array(
+          '#type' => 'select',
+          '#title' => t('Default time zone'),
+          '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', NULL),
+          '#options' => date_zone_names(),
+          '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
+        );
+      }
+      else {
+        $form['timezone']['timezone'] = array(
+          '#type' => 'hidden',
+          '#value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', NULL),
+        );
+        $form['timezone']['offset'] = array(
+          '#type' => 'select',
+          '#title' => t('Default time zone'),
+          '#default_value' =>strlen($edit['offset']) ? $edit['offset'] : variable_get('date_default_offset', NULL),
+          '#options' => date_zone_offsets(),
+          '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
+        );
+      }
     }
-
     return $form;
   }
+  elseif ($type == 'submit') {
+    date_update_userzone($edit, $user);
+  }
 }
 
 /**
@@ -542,17 +563,6 @@
   return $output;
 }
 
-function _system_zonelist() {
-  $timestamp = 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);
-  }
-  return $zones;
-}
-
 function system_site_information_settings() {
   $form['site_name'] = array(
     '#type' => 'textfield',
@@ -818,6 +828,102 @@
   return system_settings_form($form);
 }
 
+/**
+ * Test whether the system can use native php timezone handling.
+ * @todo This may need more than just a version comparison.
+ */
+function date_handle_timezones() {
+  return version_compare(PHP_VERSION, '5.1', '>');
+}
+
+function date_zone_names() {
+  $zone_names = array();
+  if (date_handle_timezones()) {
+    $zone_names = drupal_map_assoc(DateTimeZone::listIdentifiers());
+    // Make sure it is possible to leave timezone unset.
+    $zone_names = array('' => '') + $zone_names;
+  }
+    // Create a method for other modules to intervene in timezone listing.
+  foreach (module_implements('timezone_alter') as $name) {
+    $function = $name .'_timezone_alter';
+    $zone_names = $function('zone names', array('zone_names' => $zone_names));
+  }
+  return $zone_names;
+}
+
+function date_zone_offsets() {
+  $timestamp = 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);
+  }
+  return $zones;
+}
+
+function date_update_sitezone(&$form, &$form_state) {
+  if (!isset($form_state['values']['date_default_timezone'])) return;
+  $timezone = $form_state['values']['date_default_timezone'];
+  if (date_handle_timezones()) {
+    if (!empty($timezone)) {
+      variable_set('date_default_timezone', $timezone);
+    }
+    else {
+      $timezone = variable_get('date_default_timezone', NULL);
+    }
+    $dateTimeZone = new DateTimeZone($timezone);
+    $dateTime = new DateTime("now", $dateTimeZone);
+    variable_set('date_default_offset', $dateTimeZone->getOffset($dateTime));
+    $form['date_default_offset'] = $dateTimeZone->getOffset($dateTime);
+    $form_state['values']['date_default_offset'] = $dateTimeZone->getOffset($dateTime);
+  }
+  // Create a method for other modules to intervene when the site timezone changes.
+  foreach (module_implements('timezone_alter') as $name) {
+    $function = $name .'_timezone_alter';
+    $result = $function('site update', array(
+      'form' => $form,
+      'form_state' => $form_state,
+      'timezone' => $timezone,
+      'dateTimeZone' => $dateTimeZone,
+      'dateTime' => $dateTime));
+  }
+}
+
+function date_update_userzone(&$edit, &$user) {
+  if (!isset($edit['timezone'])) return;
+  $timezone = $edit['timezone'];
+  $uid = $user->uid;
+  if (date_handle_timezones()) {
+    if (!empty($uid) && !empty($timezone)) {
+      // Calling this with a uid will update that user's offset.
+      $dateTimeZone = new DateTimeZone($timezone);
+      $dateTime = new DateTime("now", $dateTimeZone);
+      db_query("UPDATE {users} SET timezone = '%s', offset = '%s' WHERE uid = %d", $timezone, $dateTimeZone->getOffset($dateTime), $uid);
+      $edit['offset'] = $dateTimeZone->getOffset($dateTime);
+    }
+    else {
+      // Calling this with an empty uid will update the offsets for all users.
+      $result = db_query("SELECT DISTINCT timezone FROM {users}");
+      while ($row = db_fetch_array($result)) {
+        $dateTimeZone = new DateTimeZone($row['timezone']);
+        $dateTime = new DateTime("now", $dateTimeZone);
+        db_query("UPDATE {users} SET offset = '%s' WHERE timezone = '%s'", $dateTimeZone->getOffset($dateTime), $row['timezone']);
+      }
+    }
+  }
+  // Create a method for other modules to intervene when the user timezone changes.
+  foreach (module_implements('timezone_alter') as $name) {
+    $function = $name .'_timezone_alter';
+    $result = $function('user update', array(
+      'edit' => $edit,
+      'user' => $user,
+      'timezone' => $timezone,
+      'dateTimeZone' => $dateTimeZone,
+      'dateTime' => $dateTime));
+  }
+}
+
 function system_date_time_settings() {
   drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
   drupal_add_js(array('dateTime' => array('lookup' => url('admin/settings/date-time/lookup'))), 'setting');
@@ -827,7 +933,7 @@
   $(document).ready(Drupal.dateTimeAutoAttach);
 }', 'inline');
   // Date settings:
-  $zones = _system_zonelist();
+  $zones = date_zone_offsets();
 
   // Date settings: possible date formats
   $date_short = array('Y-m-d H:i', 'm/d/Y - H:i', 'd/m/Y - H:i', 'Y/m/d - H:i',
@@ -859,13 +965,32 @@
     '#title' => t('Locale settings'),
   );
 
-  $form['locale']['date_default_timezone'] = array(
-    '#type' => 'select',
-    '#title' => t('Default time zone'),
-    '#default_value' => variable_get('date_default_timezone', 0),
-    '#options' => $zones,
-    '#description' => t('Select the default site time zone.')
-  );
+  if (date_handle_timezones()) {
+    $form['locale']['date_default_offset'] = array(
+      '#type' => 'hidden',
+      '#value' => variable_get('date_default_offset', NULL),
+    );
+    $form['locale']['date_default_timezone'] = array(
+      '#type' => 'select',
+      '#title' => t('Default time zone'),
+      '#default_value' => variable_get('date_default_timezone', NULL),
+      '#options' => date_zone_names(),
+      '#description' => t('Select the default site time zone.'),
+    );
+  }
+  else {
+    $form['locale']['date_default_timezone'] = array(
+      '#type' => 'hidden',
+      '#value' => variable_get('date_default_timezone', NULL),
+    );
+    $form['locale']['date_default_offset'] = array(
+      '#type' => 'select',
+      '#title' => t('Default time zone'),
+      '#default_value' => variable_get('date_default_offset', NULL),
+      '#options' => date_zone_offsets(),
+      '#description' => t('Select the default site time zone.'),
+    );
+  }
 
   $form['locale']['configurable_timezones'] = array(
     '#type' => 'radios',
@@ -973,6 +1098,7 @@
   if ($form_state['values']['date_format_long'] == 'custom') {
     $form_state['values']['date_format_long'] = $form_state['values']['date_format_long_custom'];
   }
+  date_update_sitezone($form, $form_state);
   return system_settings_form_submit($form, $form_state);
 }
 
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.809
diff -u -r1.809 user.module
--- modules/user/user.module	28 Jun 2007 07:48:41 -0000	1.809
+++ modules/user/user.module	28 Jun 2007 21:08:31 -0000
@@ -478,7 +478,7 @@
     }
     else {
       // Make sure we return the default fields at least
-      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'language', 'init', 'data');
+      $fields = array('uid', 'name', 'pass', 'mail', 'picture', 'mode', 'sort', 'threshold', 'theme', 'signature', 'created', 'access', 'login', 'status', 'timezone', 'offset', 'language', 'init', 'data');
     }
   }
 
@@ -2809,7 +2809,6 @@
   }
 
   usort($categories, '_user_sort');
-
   return $categories;
 }
 
Index: modules/user/user.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.schema,v
retrieving revision 1.2
diff -u -r1.2 user.schema
--- modules/user/user.schema	15 Jun 2007 07:15:25 -0000	1.2
+++ modules/user/user.schema	28 Jun 2007 11:59:25 -0000
@@ -58,7 +58,8 @@
       'access'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'login'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'status'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
-      'timezone'  => array('type' => 'varchar', 'length' => 8, 'not null' => FALSE),
+      'timezone'  => array('type' => 'varchar', 'length' => 50, 'not null' => FALSE),
+      'offset'    => array('type' => 'varchar', 'length' => 8, 'not null' => FALSE),
       'language'  => array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => ''),
       'picture'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'init'      => array('type' => 'varchar', 'length' => 64, 'not null' => FALSE, 'default' => ''),
@@ -66,7 +67,7 @@
     ),
     'indexes' => array(
       'access'  => array('access'),
-      'created' => array('created')
+      'created' => array('created'),
     ),
     'unique keys' => array('name' => array('name')),
     'primary key' => array('uid'),
