From 5879c09ca046c483d4102f1dd21babfac1cd8057 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Wed, 04 Jan 2012 07:47:50 -0500
Subject: [PATCH] Use proper timezones from PHP's internal timezonedb (#1485592)

---
 CHANGELOG                             |    1 
 program/include/main.inc              |   46 ++++++---------
 program/steps/settings/func.inc       |   71 ++++++-----------------
 config/main.inc.php.dist              |    5 -
 program/include/rcube_config.php      |   30 +++++++--
 program/steps/settings/save_prefs.inc |    3 
 6 files changed, 65 insertions(+), 91 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 09c8708..31f69d8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Use proper timezones from PHP's internal timezonedb (#1485592)
 - Add separate pagesize setting for mail messages and contacts (#1488269)
 - Fix handling of INBOX's subfolders in special folders config (#1488279)
 - Add ifModule statement for setting Options -Indexes in .htaccess file (#1488274)
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 691c5be..b1ae9a1 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -661,10 +661,9 @@
 $rcmail_config['addressbook_pagesize'] = 50;
 
 // use this timezone to display date/time
+// valid timezone identifers are listed here: php.net/manual/en/timezones.php
+// 'auto' will use the browser's timezone settings
 $rcmail_config['timezone'] = 'auto';
-
-// is daylight saving On? Default: (bool)date('I');
-$rcmail_config['dst_active'] = null;
 
 // prefer displaying HTML messages
 $rcmail_config['prefer_html'] = true;
diff --git a/program/include/main.inc b/program/include/main.inc
index ac804bd..ad41a13 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -1062,22 +1062,16 @@
   if (empty($ts))
     return '';
 
-  if ($convert) {
-    // get user's timezone offset
-    $tz = $RCMAIL->config->get_timezone();
+  $date = new DateTime;
+  $date->setTimestamp($ts);
 
-    // convert time to user's timezone
-    $timestamp = $ts - date('Z', $ts) + ($tz * 3600);
+  // convert to the right timezone
+  $stz = date_default_timezone_get();
+  $tz = new DateTimeZone($convert ? $RCMAIL->config->get('timezone') : 'GMT');
+  date_default_timezone_set($tz->getName());
+  $date->setTimezone($tz);
 
-    // get current timestamp in user's timezone
-    $now = time();  // local time
-    $now -= (int)date('Z'); // make GMT time
-    $now += ($tz * 3600); // user's time
-  }
-  else {
-    $now       = time();
-    $timestamp = $ts;
-  }
+  $timestamp = $date->getTimestamp();
 
   // define date format depending on current time
   if (!$format) {
@@ -1098,6 +1092,7 @@
   // strftime() format
   if (preg_match('/%[a-z]+/i', $format)) {
     $format = strftime($format, $timestamp);
+    date_default_timezone_set($stz);
     return $today ? (rcube_label('today') . ' ' . $format) : $format;
   }
 
@@ -1113,20 +1108,20 @@
       $out .= $format[$i];
     // weekday (short)
     else if ($format[$i]=='D')
-      $out .= rcube_label(strtolower(date('D', $timestamp)));
+      $out .= rcube_label(strtolower($date->format('D')));
     // weekday long
     else if ($format[$i]=='l')
-      $out .= rcube_label(strtolower(date('l', $timestamp)));
+      $out .= rcube_label(strtolower($date->format('l')));
     // month name (short)
     else if ($format[$i]=='M')
-      $out .= rcube_label(strtolower(date('M', $timestamp)));
+      $out .= rcube_label(strtolower($date->format('M')));
     // month name (long)
     else if ($format[$i]=='F')
-      $out .= rcube_label('long'.strtolower(date('M', $timestamp)));
+      $out .= rcube_label('long'.strtolower($date->format('M')));
     else if ($format[$i]=='x')
       $out .= strftime('%x %X', $timestamp);
     else
-      $out .= date($format[$i], $timestamp);
+      $out .= $date->format($format[$i]);
   }
 
   if ($today) {
@@ -1140,6 +1135,7 @@
     }
   }
 
+  date_default_timezone_set($stz);
   return $out;
 }
 
@@ -1878,17 +1874,13 @@
 // Returns RFC2822 formatted current date in user's timezone
 function rcmail_user_date()
 {
-  global $RCMAIL, $CONFIG;
+  global $RCMAIL;
 
   // get user's timezone
-  $tz = $RCMAIL->config->get_timezone();
+  $tz = new DateTimeZone($RCMAIL->config->get('timezone'));
 
-  $date = time() + $tz * 60 * 60;
-  $date = gmdate('r', $date);
-  $tz   = sprintf('%+05d', intval($tz) * 100 + ($tz - intval($tz)) * 60);
-  $date = preg_replace('/[+-][0-9]{4}$/', $tz, $date);
-
-  return $date;
+  $date = new DateTime('now', $tz);
+  return $date->format('r');
 }
 
 
diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php
index f80f92c..18a90a9 100644
--- a/program/include/rcube_config.php
+++ b/program/include/rcube_config.php
@@ -93,12 +93,14 @@
 
         // set timezone auto settings values
         if ($this->prop['timezone'] == 'auto') {
-          $this->prop['dst_active'] = intval(date('I'));
-          $this->prop['_timezone_value'] = date('Z') / 3600 - $this->prop['dst_active'];
+          $this->prop['_timezone_value'] = $this->client_timezone();
         }
-        else if ($this->prop['dst_active'] === null) {
-          $this->prop['dst_active'] = intval(date('I'));
+        else if (is_numeric($this->prop['timezone'])) {
+          $this->prop['timezone'] = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0);
         }
+
+        // remove deprecated properties
+        unset($this->prop['dst_active']);
 
         // export config data
         $GLOBALS['CONFIG'] = &$this->prop;
@@ -222,8 +224,7 @@
 
         // override timezone settings with client values
         if ($this->prop['timezone'] == 'auto') {
-            $this->prop['_timezone_value'] = isset($_SESSION['timezone']) ? $_SESSION['timezone'] : $this->prop['_timezone_value'];
-            $this->prop['dst_active'] = $this->userprefs['dst_active'] = isset($_SESSION['dst_active']) ? $_SESSION['dst_active'] : $this->prop['dst_active'];
+            $this->prop['_timezone_value'] = isset($_SESSION['timezone']) ? $this->client_timezone() : $this->prop['_timezone_value'];
         }
         else if (isset($this->prop['_timezone_value']))
            unset($this->prop['_timezone_value']);
@@ -244,10 +245,16 @@
      * Special getter for user's timezone offset including DST
      *
      * @return float  Timezone offset (in hours)
+     * @deprecated
      */
     public function get_timezone()
     {
-      return floatval($this->get('timezone')) + intval($this->get('dst_active'));
+      if ($this->get('timezone')) {
+        $tz = new DateTimeZone($this->get('timezone'));
+        return $tz->getOffset(new DateTime('now')) / 3600;
+      }
+
+      return 0;
     }
 
     /**
@@ -349,4 +356,13 @@
         return empty($this->errors) ? false : join("\n", $this->errors);
     }
 
+
+    /**
+     * Internal getter for client's (browser) timezone identifier
+     */
+    private function client_timezone()
+    {
+        return isset($_SESSION['timezone']) ? timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0) : date_default_timezone_get();
+    }
+
 }
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index 2050b93..44d3610 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -177,63 +177,30 @@
     // timezone selection
     if (!isset($no_override['timezone'])) {
       $field_id = 'rcmfd_timezone';
-      $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id,
-        'onchange' => "$('#rcmfd_dst').attr('disabled', this.selectedIndex==0)"));
+      $select_timezone = new html_select(array('name' => '_timezone', 'id' => $field_id));
       $select_timezone->add(rcube_label('autodetect'), 'auto');
-      $select_timezone->add('(GMT -11:00) Midway Island, Samoa', '-11');
-      $select_timezone->add('(GMT -10:00) Hawaii', '-10');
-      $select_timezone->add('(GMT -9:30) Marquesas Islands', '-9.5');
-      $select_timezone->add('(GMT -9:00) Alaska', '-9');
-      $select_timezone->add('(GMT -8:00) Pacific Time (US/Canada)', '-8');
-      $select_timezone->add('(GMT -7:00) Mountain Time (US/Canada)', '-7');
-      $select_timezone->add('(GMT -6:00) Central Time (US/Canada), Mexico City', '-6');
-      $select_timezone->add('(GMT -5:00) Eastern Time (US/Canada), Bogota, Lima', '-5');
-      $select_timezone->add('(GMT -4:30) Caracas', '-4.5');
-      $select_timezone->add('(GMT -4:00) Atlantic Time (Canada), La Paz', '-4');
-      $select_timezone->add('(GMT -3:30) Nfld Time (Canada), Nfld, S. Labador', '-3.5');
-      $select_timezone->add('(GMT -3:00) Brazil, Buenos Aires, Georgetown', '-3');
-      $select_timezone->add('(GMT -2:00) Mid-Atlantic', '-2');
-      $select_timezone->add('(GMT -1:00) Azores, Cape Verde Islands', '-1');
-      $select_timezone->add('(GMT) Western Europe, London, Lisbon, Casablanca', '0');
-      $select_timezone->add('(GMT +1:00) Central European Time', '1');
-      $select_timezone->add('(GMT +2:00) EET: Tallinn, Helsinki, Kaliningrad, South Africa', '2');
-      $select_timezone->add('(GMT +3:00) Baghdad, Kuwait, Riyadh, Moscow, Nairobi', '3');
-      $select_timezone->add('(GMT +3:30) Tehran', '3.5');
-      $select_timezone->add('(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi', '4');
-      $select_timezone->add('(GMT +4:30) Kabul', '4.5');
-      $select_timezone->add('(GMT +5:00) Ekaterinburg, Islamabad, Karachi', '5');
-      $select_timezone->add('(GMT +5:30) Chennai, Kolkata, Mumbai, New Delhi', '5.5');
-      $select_timezone->add('(GMT +5:45) Kathmandu', '5.75');
-      $select_timezone->add('(GMT +6:00) Almaty, Dhaka, Colombo', '6');
-      $select_timezone->add('(GMT +6:30) Cocos Islands, Myanmar', '6.5');
-      $select_timezone->add('(GMT +7:00) Bangkok, Hanoi, Jakarta', '7');
-      $select_timezone->add('(GMT +8:00) Beijing, Perth, Singapore, Taipei', '8');
-      $select_timezone->add('(GMT +8:45) Caiguna, Eucla, Border Village', '8.75');
-      $select_timezone->add('(GMT +9:00) Tokyo, Seoul, Yakutsk', '9');
-      $select_timezone->add('(GMT +9:30) Adelaide, Darwin', '9.5');
-      $select_timezone->add('(GMT +10:00) EAST/AEST: Sydney, Guam, Vladivostok', '10');
-      $select_timezone->add('(GMT +10:30) New South Wales', '10.5');
-      $select_timezone->add('(GMT +11:00) Magadan, Solomon Islands', '11');
-      $select_timezone->add('(GMT +11:30) Norfolk Island', '11.5');
-      $select_timezone->add('(GMT +12:00) Auckland, Wellington, Kamchatka', '12');
-      $select_timezone->add('(GMT +12:45) Chatham Islands', '12.75');
-      $select_timezone->add('(GMT +13:00) Tonga, Pheonix Islands', '13');
-      $select_timezone->add('(GMT +14:00) Kiribati', '14');
+
+      $now = new DateTime();
+      foreach (DateTimeZone::listIdentifiers() as $i => $tzs) {
+        $tz = new DateTimeZone($tzs);
+        $date = new DateTime('2012-12-21', $tz);
+        $offset = $date->format('Z') + 45000;
+        $sortkey = sprintf('%06d.%s', $offset, $tzs);
+        $zones[$sortkey] = array($tzs, $date->format('P'));
+      }
+
+      ksort($zones);
+      foreach ($zones as $zone) {
+        list($tzs, $offset) = $zone;
+        $select_timezone->add('(GMT ' . $offset . ') ' . strtr($tzs, '_', ' '), $tzs);
+      }
+
+      if (is_numeric($config['timezone']))
+        timezone_name_from_abbr("", $config['timezone'] * 3600, 0);
 
       $blocks['main']['options']['timezone'] = array(
         'title' => html::label($field_id, Q(rcube_label('timezone'))),
         'content' => $select_timezone->show((string)$config['timezone']),
-      );
-    }
-
-    // daylight savings
-    if (!isset($no_override['dst_active'])) {
-      $field_id = 'rcmfd_dst';
-      $input_dst = new html_checkbox(array('name' => '_dst_active', 'id' => $field_id, 'value' => 1, 'disabled' => ($config['timezone'] === 'auto')));
-
-      $blocks['main']['options']['dstactive'] = array(
-        'title' => html::label($field_id, Q(rcube_label('dstactive'))),
-        'content' => $input_dst->show($config['dst_active']),
       );
     }
 
diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc
index 2e89ce1..36d401e 100644
--- a/program/steps/settings/save_prefs.inc
+++ b/program/steps/settings/save_prefs.inc
@@ -29,8 +29,7 @@
   case 'general':
     $a_user_prefs = array(
       'language'     => isset($_POST['_language']) ? get_input_value('_language', RCUBE_INPUT_POST) : $CONFIG['language'],
-      'timezone'     => isset($_POST['_timezone']) ? (is_numeric($_POST['_timezone']) ? floatval($_POST['_timezone']) : get_input_value('_timezone', RCUBE_INPUT_POST)) : $CONFIG['timezone'],
-      'dst_active'   => isset($_POST['_dst_active']) ? TRUE : FALSE,
+      'timezone'     => isset($_POST['_timezone']) ? get_input_value('_timezone', RCUBE_INPUT_POST) : $CONFIG['timezone'],
       'date_format'  => isset($_POST['_date_format']) ? get_input_value('_date_format', RCUBE_INPUT_POST) : $CONFIG['date_format'],
       'time_format'  => isset($_POST['_time_format']) ? get_input_value('_time_format', RCUBE_INPUT_POST) : ($CONFIG['time_format'] ? $CONFIG['time_format'] : 'H:i'),
       'prettydate'   => isset($_POST['_pretty_date']) ? TRUE : FALSE,

--
Gitblit v1.9.1