system/classes/timezoneconfig.class.php
author Dirk Haun <dirk@haun-online.de>
Sun, 20 Sep 2009 11:00:03 +0200
branchHEAD
changeset 7428 df55886043f2
child 7429 01f95a3e4545
permissions -rw-r--r--
Modernized the "timezone hack", made the config option a dropdown, and moved all timezone-related code into a new TimeZoneConfig class
     1 <?php
     2 
     3 /* Reminder: always indent with 4 spaces (no tabs). */
     4 // +---------------------------------------------------------------------------+
     5 // | Geeklog 1.6                                                               |
     6 // +---------------------------------------------------------------------------+
     7 // | timezoneconfig.class.php                                                  |
     8 // |                                                                           |
     9 // | Helper class for time zone handling                                       |
    10 // +---------------------------------------------------------------------------+
    11 // | Copyright (C) 2009 by the following authors:                              |
    12 // |                                                                           |
    13 // | Authors: Dirk Haun             - dirk AT haun-online DOT de               |
    14 // | based on earlier work by Oliver Spiesshofer, Yew Loong, and others        |
    15 // +---------------------------------------------------------------------------+
    16 // |                                                                           |
    17 // | This program is free software; you can redistribute it and/or             |
    18 // | modify it under the terms of the GNU General Public License               |
    19 // | as published by the Free Software Foundation; either version 2            |
    20 // | of the License, or (at your option) any later version.                    |
    21 // |                                                                           |
    22 // | This program is distributed in the hope that it will be useful,           |
    23 // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
    24 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
    25 // | GNU General Public License for more details.                              |
    26 // |                                                                           |
    27 // | You should have received a copy of the GNU General Public License         |
    28 // | along with this program; if not, write to the Free Software Foundation,   |
    29 // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
    30 // |                                                                           |
    31 // +---------------------------------------------------------------------------+
    32 
    33 /**
    34 * Geeklog Time Zone Config class
    35 *
    36 * A collection of static (for now) methods dealing with time zone handling.
    37 *
    38 * For the original "Timezone Hack" discussion, see
    39 * @link http://www.geeklog.net/forum/viewtopic.php?showtopic=21232
    40 * 
    41 * @author Dirk Haun, dirk AT haun-online DOT de
    42 * 
    43 */
    44 class TimeZoneConfig {
    45 
    46     /**
    47     * Set the system's timezone
    48     *
    49     * @param    string  $tz     timezone to set; use $_CONF['timezone'] if empty
    50     * @return   void
    51     * @static
    52     *
    53     */
    54     function setSystemTimeZone($tz = '')
    55     {
    56         global $_CONF;
    57 
    58         if (empty($tz) && !empty($_CONF['timezone'])) {
    59             $tz = $_CONF['timezone'];
    60         }
    61 
    62         if (! empty($tz)) {
    63             if (function_exists('date_default_timezone_set')) {
    64                 if (! @date_default_timezone_set($tz)) {
    65                     date_default_timezone_set('UTC');
    66                     COM_errorLog("Timezone '$tz' not valid - using 'UTC' instead", 1);
    67                 }
    68             } elseif (!ini_get('safe_mode') && function_exists('putenv')) {
    69                 // aka "Timezone Hack"
    70                 putenv('TZ=' . $tz);
    71             }
    72         } elseif (function_exists('date_default_timezone_get')) {
    73             // this is not ideal but will stop PHP 5.3.0ff from complaining ...
    74             date_default_timezone_set(@date_default_timezone_get());
    75         }
    76     }
    77 
    78     /**
    79     * Get the user's preferred timezone
    80     *
    81     * @return   string  name of the timezone
    82     * @static
    83     *
    84     */
    85     function getUserTimeZone()
    86     {
    87         global $_CONF, $_USER;
    88 
    89         if (! empty($_USER['tzid'])) {
    90             $timezone = $_USER['tzid'];
    91         } elseif (! empty($_CONF['timezone'])) {
    92             $timezone = $_CONF['timezone'];
    93         } else {
    94             require_once 'Date/TimeZone.php';
    95 
    96             $tz_obj = Date_TimeZone::getDefault();
    97             $timezone = $tz_obj->id;
    98         }
    99 
   100         return $timezone;
   101     }
   102 
   103     /**
   104     * Provide a dropdown menu of the available timezones
   105     *
   106     * @return   string  HTML for the dropdown
   107     * @static
   108     *
   109     */
   110     function getTimeZoneDropDown($selected = '', $attributes = array())
   111     {
   112         $timezones = TimeZoneConfig::listAvailableTimeZones();
   113 
   114         $selection = '<select';
   115         foreach ($attributes as $name => $value) {
   116             $selection .= sprintf(' %s="%s"', $name, $value);
   117         }
   118         $selection .= '>' . LB;
   119 
   120         foreach ($timezones as $tzid => $tzdisplay) {
   121             $selection .= '<option value="' . $tzid . '"';
   122             if (!empty($selected) && ($selected == $tzid)) {
   123                 $selection .= ' selected="selected"';
   124             }
   125             $selection .= ">$tzdisplay</option>" . LB;
   126         }
   127         $selection .= '</select>';
   128 
   129         return $selection;
   130     }
   131 
   132     /**
   133     * Provide a list of available timezones
   134     *
   135     * @return   array   array of (timezone-short-name, timezone-long-name) pairs
   136     * @static
   137     *
   138     */
   139     function listAvailableTimeZones()
   140     {
   141         $timezones = array();
   142 
   143         // use only timezones that contain one of these
   144         $useonly = array('Africa', 'America', 'Antarctica', 'Arctic', 'Asia',
   145                          'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific',
   146                          'UTC');
   147 
   148         // check if we can use the DateTimeZone class
   149         $useDateTimeZone = false;
   150         if (class_exists('DateTimeZone') && class_exists('ReflectionClass')) {
   151             $rc = new ReflectionClass('DateTimeZone');
   152             if ($rc->hasMethod('listAbbreviations')) {
   153                 $useDateTimeZone = true;
   154             }
   155         }
   156 
   157         if ($useDateTimeZone) {
   158 
   159             $T = DateTimeZone::listAbbreviations();
   160             foreach ($T as $tzid => $entries) {
   161                 $shortname = strtoupper($tzid);
   162                 foreach ($entries as $data) {
   163                     $tzcheck = explode('/', $data['timezone_id']);
   164                     if (! in_array($tzcheck[0], $useonly)) {
   165                         continue;
   166                     }
   167 
   168                     $hours = $data['offset'] / 3600;
   169                     $hours = ((int) ($hours * 100) / 100);
   170                     if ($hours > 0) {
   171                         $hours = "+$hours";
   172                     }
   173 
   174                     $tzcode = str_replace('_', ' ', $data['timezone_id']);
   175                     $tzcode = htmlspecialchars($tzcode);
   176                     $formattedTimezone = "$hours, $shortname ($tzcode)";
   177                     $timezones[$data['timezone_id']] = $formattedTimezone;
   178                 }
   179             }
   180 
   181         } else { // DateTimeZone not available - use PEAR Date class
   182 
   183             require_once 'Date/TimeZone.php';
   184 
   185             $T = $GLOBALS['_DATE_TIMEZONE_DATA'];
   186 
   187             foreach ($T as $tzid => $tDetails) {
   188                 $tzcheck = explode('/', $tzid);
   189                 if (! in_array($tzcheck[0], $useonly)) {
   190                     continue;
   191                 }
   192                 if (!empty($tzcheck[1]) &&
   193                         (strpos($tzcheck[1], 'Riyadh') === 0)) {
   194                     // these time zones are based on solar time and not widely
   195                     // supported - skip
   196                     continue;
   197                 }
   198 
   199                 $tzcode = str_replace('_', ' ', $tzid);
   200                 $tzcode = htmlspecialchars($tzcode);
   201                 $hours = $tDetails['offset'] / (3600 * 1000);
   202                 $hours = ((int) ($hours * 100) / 100);
   203                 if ($hours > 0) {
   204                     $hours = "+$hours";
   205                 }
   206 
   207                 $formattedTimezone = "$hours, {$tDetails['shortname']} ($tzcode)";
   208                 $timezones[$tzid] = $formattedTimezone;
   209             }
   210 
   211         }
   212 
   213         uasort($timezones, 'TimeZoneConfig::_sort_by_timezone');
   214 
   215         return $timezones;
   216     }
   217 
   218     /**
   219     * Helper method: Sort timezone entries
   220     *
   221     * @param    string  $tz1    first timezone
   222     * @param    string  $tz2    second timezone
   223     * @return   int             0: equal, <0: first<second, >0: first>second
   224     * @static
   225     * @access   private
   226     *
   227     */
   228     function _sort_by_timezone($tz1, $tz2)
   229     {
   230         $p1 = explode(',', $tz1);
   231         $p2 = explode(',', $tz2);
   232 
   233         // compare offsets
   234         $o1 = $p1[0];
   235         $o2 = $p2[0];
   236         if ($o1 != $o2) {
   237             return ($o1 < $o2 ? -1 : 1);
   238         }
   239 
   240         // drop offset, pop timezone name, then add it to the end again
   241         array_shift($p1);
   242         $tz1 = trim(implode(',', $p1));
   243         $p1 = explode(' ', $tz1);
   244         $x1 = array_shift($p1);
   245         $p1[] = $x1;
   246         $tz1 = implode(' ', $p1);
   247 
   248         array_shift($p2);
   249         $tz2 = trim(implode(',', $p2));
   250         $p2 = explode(' ', $tz2);
   251         $x2 = array_shift($p2);
   252         $p2[] = $x2;
   253         $tz2 = implode(' ', $p2);
   254 
   255         return strcmp($tz1, $tz2);
   256     }
   257 
   258 }
   259 
   260 ?>