Differences Between: [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Core date and time related code. 19 * 20 * @package core 21 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 * @author Petr Skoda <petr.skoda@totaralms.com> 24 */ 25 26 /** 27 * Core date and time related code. 28 * 29 * @since Moodle 2.9 30 * @package core 31 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/} 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 * @author Petr Skoda <petr.skoda@totaralms.com> 34 */ 35 class core_date { 36 /** @var array list of recommended zones */ 37 protected static $goodzones = null; 38 39 /** @var array list of BC zones supported by PHP */ 40 protected static $bczones = null; 41 42 /** @var array mapping of timezones not supported by PHP */ 43 protected static $badzones = null; 44 45 /** @var string the default PHP timezone right after config.php */ 46 protected static $defaultphptimezone = null; 47 48 /** 49 * Returns a localised list of timezones. 50 * @param string $currentvalue 51 * @param bool $include99 should the server timezone info be included? 52 * @return array 53 */ 54 public static function get_list_of_timezones($currentvalue = null, $include99 = false) { 55 self::init_zones(); 56 57 // Localise first. 58 $timezones = array(); 59 foreach (self::$goodzones as $tzkey => $ignored) { 60 $timezones[$tzkey] = self::get_localised_timezone($tzkey); 61 } 62 core_collator::asort($timezones); 63 64 // Add '99' if requested. 65 if ($include99 or $currentvalue == 99) { 66 $timezones['99'] = self::get_localised_timezone('99'); 67 } 68 69 if (!isset($currentvalue) or isset($timezones[$currentvalue])) { 70 return $timezones; 71 } 72 73 if (is_numeric($currentvalue)) { 74 // UTC offset. 75 if ($currentvalue == 0) { 76 $a = 'UTC'; 77 } else { 78 $modifier = ($currentvalue > 0) ? '+' : ''; 79 $a = 'UTC' . $modifier . number_format($currentvalue, 1); 80 } 81 $timezones[$currentvalue] = get_string('timezoneinvalid', 'core_admin', $a); 82 } else { 83 // Some string we don't recognise. 84 $timezones[$currentvalue] = get_string('timezoneinvalid', 'core_admin', $currentvalue); 85 } 86 87 return $timezones; 88 } 89 90 /** 91 * Returns localised timezone name. 92 * @param string $tz 93 * @return string 94 */ 95 public static function get_localised_timezone($tz) { 96 if ($tz == 99) { 97 $tz = self::get_server_timezone(); 98 $tz = self::get_localised_timezone($tz); 99 return get_string('timezoneserver', 'core_admin', $tz); 100 } 101 102 if (get_string_manager()->string_exists(strtolower($tz), 'core_timezones')) { 103 $tz = get_string(strtolower($tz), 'core_timezones'); 104 } else if ($tz === 'GMT' or $tz === 'Etc/GMT' or $tz === 'Etc/UTC') { 105 $tz = 'UTC'; 106 } else if (preg_match('|^Etc/GMT([+-])([0-9]+)$|', $tz, $matches)) { 107 $sign = $matches[1] === '+' ? '-' : '+'; 108 $tz = 'UTC' . $sign . $matches[2]; 109 } 110 111 return $tz; 112 } 113 114 /** 115 * Normalise the timezone name. If timezone not supported 116 * this method falls back to server timezone (if valid) 117 * or default PHP timezone. 118 * 119 * @param int|string|float|DateTimeZone $tz 120 * @return string timezone compatible with PHP 121 */ 122 public static function normalise_timezone($tz) { 123 global $CFG; 124 125 if ($tz instanceof DateTimeZone) { 126 return $tz->getName(); 127 } 128 129 self::init_zones(); 130 $tz = (string)$tz; 131 132 if (isset(self::$goodzones[$tz]) or isset(self::$bczones[$tz])) { 133 return $tz; 134 } 135 136 $fixed = false; 137 if (isset(self::$badzones[$tz])) { 138 // Convert to known zone. 139 $tz = self::$badzones[$tz]; 140 $fixed = true; 141 } else if (is_numeric($tz)) { 142 // Half hour numeric offsets were already tested, try rounding to integers here. 143 $roundedtz = (string)(int)$tz; 144 if (isset(self::$badzones[$roundedtz])) { 145 $tz = self::$badzones[$roundedtz]; 146 $fixed = true; 147 } 148 } 149 150 if ($fixed and isset(self::$goodzones[$tz]) or isset(self::$bczones[$tz])) { 151 return $tz; 152 } 153 154 // Is server timezone usable? 155 if (isset($CFG->timezone) and !is_numeric($CFG->timezone)) { 156 $result = @timezone_open($CFG->timezone); // Hide notices if invalid. 157 if ($result !== false) { 158 return $result->getName(); 159 } 160 } 161 162 // Bad luck, use the php.ini default or value set in config.php. 163 return self::get_default_php_timezone(); 164 } 165 166 /** 167 * Returns server timezone. 168 * @return string normalised timezone name compatible with PHP 169 **/ 170 public static function get_server_timezone() { 171 global $CFG; 172 173 if (!isset($CFG->timezone) or $CFG->timezone == 99 or $CFG->timezone === '') { 174 return self::get_default_php_timezone(); 175 } 176 177 return self::normalise_timezone($CFG->timezone); 178 } 179 180 /** 181 * Returns server timezone. 182 * @return DateTimeZone 183 **/ 184 public static function get_server_timezone_object() { 185 $tz = self::get_server_timezone(); 186 return new DateTimeZone($tz); 187 } 188 189 /** 190 * Set PHP default timezone to $CFG->timezone. 191 */ 192 public static function set_default_server_timezone() { 193 global $CFG; 194 195 if (!isset($CFG->timezone) or $CFG->timezone == 99 or $CFG->timezone === '') { 196 date_default_timezone_set(self::get_default_php_timezone()); 197 return; 198 } 199 200 $current = date_default_timezone_get(); 201 if ($current === $CFG->timezone) { 202 // Nothing to do. 203 return; 204 } 205 206 if (!isset(self::$goodzones)) { 207 // For better performance try do do this without full tz init, 208 // because this is called from lib/setup.php file on each page. 209 $result = @timezone_open($CFG->timezone); // Ignore error if setting invalid. 210 if ($result !== false) { 211 date_default_timezone_set($result->getName()); 212 return; 213 } 214 } 215 216 // Slow way is the last option. 217 date_default_timezone_set(self::get_server_timezone()); 218 } 219 220 /** 221 * Returns user timezone. 222 * 223 * Ideally the parameter should be a real user record, 224 * unfortunately the legacy code is using 99 for both server 225 * and default value. 226 * 227 * Example of using legacy API: 228 * // Date for other user via legacy API. 229 * $datestr = userdate($time, core_date::get_user_timezone($user)); 230 * 231 * The coding style rules in Moodle are moronic, 232 * why cannot the parameter names have underscores in them? 233 * 234 * @param mixed $userorforcedtz user object or legacy forced timezone string or tz object 235 * @return string normalised timezone name compatible with PHP 236 */ 237 public static function get_user_timezone($userorforcedtz = null) { 238 global $USER, $CFG; 239 240 if ($userorforcedtz instanceof DateTimeZone) { 241 return $userorforcedtz->getName(); 242 } 243 244 if (isset($userorforcedtz) and !is_object($userorforcedtz) and $userorforcedtz != 99) { 245 // Legacy code is forcing timezone in legacy API. 246 return self::normalise_timezone($userorforcedtz); 247 } 248 249 if (isset($CFG->forcetimezone) and $CFG->forcetimezone != 99) { 250 // Override any user timezone. 251 return self::normalise_timezone($CFG->forcetimezone); 252 } 253 254 if ($userorforcedtz === null) { 255 $tz = isset($USER->timezone) ? $USER->timezone : 99; 256 257 } else if (is_object($userorforcedtz)) { 258 $tz = isset($userorforcedtz->timezone) ? $userorforcedtz->timezone : 99; 259 260 } else { 261 if ($userorforcedtz == 99) { 262 $tz = isset($USER->timezone) ? $USER->timezone : 99; 263 } else { 264 $tz = $userorforcedtz; 265 } 266 } 267 268 if ($tz == 99) { 269 return self::get_server_timezone(); 270 } 271 272 return self::normalise_timezone($tz); 273 } 274 275 /** 276 * Return user timezone object. 277 * 278 * @param mixed $userorforcedtz 279 * @return DateTimeZone 280 */ 281 public static function get_user_timezone_object($userorforcedtz = null) { 282 $tz = self::get_user_timezone($userorforcedtz); 283 return new DateTimeZone($tz); 284 } 285 286 /** 287 * Return default timezone set in php.ini or config.php. 288 * @return string normalised timezone compatible with PHP 289 */ 290 public static function get_default_php_timezone() { 291 if (!isset(self::$defaultphptimezone)) { 292 // This should not happen. 293 self::store_default_php_timezone(); 294 } 295 296 return self::$defaultphptimezone; 297 } 298 299 /** 300 * To be called from lib/setup.php only! 301 */ 302 public static function store_default_php_timezone() { 303 if ((defined('PHPUNIT_TEST') and PHPUNIT_TEST) 304 or defined('BEHAT_SITE_RUNNING') or defined('BEHAT_TEST') or defined('BEHAT_UTIL')) { 305 // We want all test sites to be consistent by default. 306 self::$defaultphptimezone = 'Australia/Perth'; 307 return; 308 } 309 if (!isset(self::$defaultphptimezone)) { 310 self::$defaultphptimezone = date_default_timezone_get(); 311 } 312 } 313 314 /** 315 * Do not use directly - use $this->setTimezone('xx', $tz) instead in your test case. 316 * @param string $tz valid timezone name 317 */ 318 public static function phpunit_override_default_php_timezone($tz) { 319 if (!defined('PHPUNIT_TEST')) { 320 throw new coding_exception('core_date::phpunit_override_default_php_timezone() must be used only from unit tests'); 321 } 322 $result = timezone_open($tz); // This triggers error if $tz invalid. 323 if ($result !== false) { 324 self::$defaultphptimezone = $tz; 325 } else { 326 self::$defaultphptimezone = 'Australia/Perth'; 327 } 328 } 329 330 /** 331 * To be called from phpunit reset only, after restoring $CFG. 332 */ 333 public static function phpunit_reset() { 334 global $CFG; 335 if (!defined('PHPUNIT_TEST')) { 336 throw new coding_exception('core_date::phpunit_reset() must be used only from unit tests'); 337 } 338 self::store_default_php_timezone(); 339 date_default_timezone_set($CFG->timezone); 340 } 341 342 /** 343 * Initialise timezone arrays, call before use. 344 */ 345 protected static function init_zones() { 346 if (isset(self::$goodzones)) { 347 return; 348 } 349 350 $zones = DateTimeZone::listIdentifiers(); 351 self::$goodzones = array_fill_keys($zones, true); 352 353 $zones = DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC); 354 self::$bczones = array(); 355 foreach ($zones as $zone) { 356 if (isset(self::$goodzones[$zone])) { 357 continue; 358 } 359 self::$bczones[$zone] = true; 360 } 361 362 self::$badzones = array( 363 // Windows time zones. 364 'Dateline Standard Time' => 'Etc/GMT+12', 365 'Hawaiian Standard Time' => 'Pacific/Honolulu', 366 'Alaskan Standard Time' => 'America/Anchorage', 367 'Pacific Standard Time (Mexico)' => 'America/Tijuana', 368 'Pacific Standard Time' => 'America/Los_Angeles', 369 'US Mountain Standard Time' => 'America/Phoenix', 370 'Mountain Standard Time (Mexico)' => 'America/Chihuahua', 371 'Mountain Standard Time' => 'America/Denver', 372 'Central America Standard Time' => 'America/Guatemala', 373 'Central Standard Time' => 'America/Chicago', 374 'Central Standard Time (Mexico)' => 'America/Mexico_City', 375 'Canada Central Standard Time' => 'America/Regina', 376 'SA Pacific Standard Time' => 'America/Bogota', 377 'S.A. Pacific Standard Time' => 'America/Bogota', 378 'Eastern Standard Time' => 'America/New_York', 379 'US Eastern Standard Time' => 'America/Indiana/Indianapolis', 380 'U.S. Eastern Standard Time' => 'America/Indiana/Indianapolis', 381 'Venezuela Standard Time' => 'America/Caracas', 382 'Paraguay Standard Time' => 'America/Asuncion', 383 'Atlantic Standard Time' => 'America/Halifax', 384 'Central Brazilian Standard Time' => 'America/Cuiaba', 385 'SA Western Standard Time' => 'America/La_Paz', 386 'S.A. Western Standard Time' => 'America/La_Paz', 387 'Pacific SA Standard Time' => 'America/Santiago', 388 'Pacific S.A. Standard Time' => 'America/Santiago', 389 'Newfoundland Standard Time' => 'America/St_Johns', 390 'Newfoundland and Labrador Standard Time' => 'America/St_Johns', 391 'E. South America Standard Time' => 'America/Sao_Paulo', 392 'Argentina Standard Time' => 'America/Argentina/Buenos_Aires', 393 'SA Eastern Standard Time' => 'America/Cayenne', 394 'S.A. Eastern Standard Time' => 'America/Cayenne', 395 'Greenland Standard Time' => 'America/Godthab', 396 'Montevideo Standard Time' => 'America/Montevideo', 397 'Bahia Standard Time' => 'America/Bahia', 398 'Azores Standard Time' => 'Atlantic/Azores', 399 'Cape Verde Standard Time' => 'Atlantic/Cape_Verde', 400 'Morocco Standard Time' => 'Africa/Casablanca', 401 'GMT Standard Time' => 'Europe/London', 402 'Greenwich Standard Time' => 'Atlantic/Reykjavik', 403 'W. Europe Standard Time' => 'Europe/Berlin', 404 'Central Europe Standard Time' => 'Europe/Budapest', 405 'Romance Standard Time' => 'Europe/Paris', 406 'Central European Standard Time' => 'Europe/Warsaw', 407 'W. Central Africa Standard Time' => 'Africa/Lagos', 408 'Namibia Standard Time' => 'Africa/Windhoek', 409 'Jordan Standard Time' => 'Asia/Amman', 410 'GTB Standard Time' => 'Europe/Bucharest', 411 'Middle East Standard Time' => 'Asia/Beirut', 412 'Egypt Standard Time' => 'Africa/Cairo', 413 'Syria Standard Time' => 'Asia/Damascus', 414 'South Africa Standard Time' => 'Africa/Johannesburg', 415 'FLE Standard Time' => 'Europe/Kiev', 416 'Turkey Standard Time' => 'Europe/Istanbul', 417 'Israel Standard Time' => 'Asia/Jerusalem', 418 'Kaliningrad Standard Time' => 'Europe/Kaliningrad', 419 'Libya Standard Time' => 'Africa/Tripoli', 420 'Arabic Standard Time' => 'Asia/Baghdad', 421 'Arab Standard Time' => 'Asia/Riyadh', 422 'Belarus Standard Time' => 'Europe/Minsk', 423 'Russian Standard Time' => 'Europe/Moscow', 424 'E. Africa Standard Time' => 'Africa/Nairobi', 425 'Iran Standard Time' => 'Asia/Tehran', 426 'Arabian Standard Time' => 'Asia/Dubai', 427 'Azerbaijan Standard Time' => 'Asia/Baku', 428 'Russia Time Zone 3' => 'Europe/Samara', 429 'Mauritius Standard Time' => 'Indian/Mauritius', 430 'Georgian Standard Time' => 'Asia/Tbilisi', 431 'Caucasus Standard Time' => 'Asia/Yerevan', 432 'Afghanistan Standard Time' => 'Asia/Kabul', 433 'West Asia Standard Time' => 'Asia/Tashkent', 434 'Ekaterinburg Standard Time' => 'Asia/Yekaterinburg', 435 'Pakistan Standard Time' => 'Asia/Karachi', 436 'India Standard Time' => 'Asia/Kolkata', // PHP and Windows differ in spelling. 437 'Sri Lanka Standard Time' => 'Asia/Colombo', 438 'Nepal Standard Time' => 'Asia/Kathmandu', 439 'Central Asia Standard Time' => 'Asia/Almaty', 440 'Bangladesh Standard Time' => 'Asia/Dhaka', 441 'N. Central Asia Standard Time' => 'Asia/Novosibirsk', 442 'Myanmar Standard Time' => 'Asia/Yangon', 443 'SE Asia Standard Time' => 'Asia/Bangkok', 444 'S.E. Asia Standard Time' => 'Asia/Bangkok', 445 'North Asia Standard Time' => 'Asia/Krasnoyarsk', 446 'China Standard Time' => 'Asia/Shanghai', 447 'North Asia East Standard Time' => 'Asia/Irkutsk', 448 'Singapore Standard Time' => 'Asia/Singapore', 449 'W. Australia Standard Time' => 'Australia/Perth', 450 'Taipei Standard Time' => 'Asia/Taipei', 451 'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar', 452 'Tokyo Standard Time' => 'Asia/Tokyo', 453 'Korea Standard Time' => 'Asia/Seoul', 454 'Yakutsk Standard Time' => 'Asia/Yakutsk', 455 'Cen. Australia Standard Time' => 'Australia/Adelaide', 456 'AUS Central Standard Time' => 'Australia/Darwin', 457 'A.U.S. Central Standard Time' => 'Australia/Darwin', 458 'E. Australia Standard Time' => 'Australia/Brisbane', 459 'AUS Eastern Standard Time' => 'Australia/Sydney', 460 'A.U.S. Eastern Standard Time' => 'Australia/Sydney', 461 'West Pacific Standard Time' => 'Pacific/Port_Moresby', 462 'Tasmania Standard Time' => 'Australia/Hobart', 463 'Magadan Standard Time' => 'Asia/Magadan', 464 'Vladivostok Standard Time' => 'Asia/Vladivostok', 465 'Russia Time Zone 10' => 'Asia/Srednekolymsk', 466 'Central Pacific Standard Time' => 'Pacific/Guadalcanal', 467 'Russia Time Zone 11' => 'Asia/Kamchatka', 468 'New Zealand Standard Time' => 'Pacific/Auckland', 469 'Fiji Standard Time' => 'Pacific/Fiji', 470 'Fiji Islands Standard Time' => 'Pacific/Fiji', 471 'Tonga Standard Time' => 'Pacific/Tongatapu', 472 'Samoa Standard Time' => 'Pacific/Apia', 473 'Line Islands Standard Time' => 'Pacific/Kiritimati', 474 'Mexico Standard Time 2' => 'America/Chihuahua', 475 'Mexico Standard Time' => 'America/Mexico_City', 476 'U.S. Mountain Standard Time' => 'America/Phoenix', 477 'Mid-Atlantic Standard Time' => 'Atlantic/South_Georgia', 478 'E. Europe Standard Time' => 'Europe/Minsk', 479 'Transitional Islamic State of Afghanistan Standard Time' => 'Asia/Kabul', 480 'Armenian Standard Time' => 'Asia/Yerevan', 481 'Kamchatka Standard Time' => 'Asia/Kamchatka', 482 483 // A lot more bad legacy (deprecated) time zones. 484 'Australia/ACT' => 'Australia/Sydney', 485 'Australia/LHI' => 'Australia/Lord_Howe', 486 'Australia/North' => 'Australia/Darwin', 487 'Australia/NSW' => 'Australia/Sydney', 488 'Australia/Queensland' => 'Australia/Brisbane', 489 'Australia/South' => 'Australia/Adelaide', 490 'Australia/Tasmania' => 'Australia/Hobart', 491 'Australia/Victoria' => 'Australia/Melbourne', 492 'Australia/West' => 'Australia/Perth', 493 'Brazil/Acre' => 'America/Rio_Branco', 494 'Brazil/DeNoronha' => 'America/Noronha', 495 'Brazil/East' => 'America/Sao_Paulo', 496 'Brazil/West' => 'America/Manaus', 497 'Canada/Atlantic' => 'America/Halifax', 498 'Canada/Central' => 'America/Winnipeg', 499 'Canada/Eastern' => 'America/Toronto', 500 'Canada/Mountain' => 'America/Edmonton', 501 'Canada/Newfoundland' => 'America/St_Johns', 502 'Canada/Pacific' => 'America/Vancouver', 503 'Canada/Saskatchewan' => 'America/Regina', 504 'Canada/Yukon' => 'America/Whitehorse', 505 'CDT' => 'America/Chicago', 506 'CET' => 'Europe/Berlin', 507 'Central European Time' => 'Europe/Berlin', 508 'Central Time' => 'America/Chicago', 509 'Chile/Continental' => 'America/Santiago', 510 'Chile/EasterIsland' => 'Pacific/Easter', 511 'China Time' => 'Asia/Shanghai', 512 'CST' => 'America/Chicago', 513 'CST6CDT' => 'America/Chicago', 514 'Cuba' => 'America/Havana', 515 'EDT' => 'America/New_York', 516 'EET' => 'Europe/Kiev', 517 'Egypt' => 'Africa/Cairo', 518 'Eire' => 'Europe/Dublin', 519 'EST' => 'America/Cancun', 520 'EST5EDT' => 'America/New_York', 521 'Eastern Time' => 'America/New_York', 522 'Etc/Greenwich' => 'Etc/GMT', 523 'Etc/UCT' => 'Etc/UTC', 524 'Etc/Universal' => 'Etc/UTC', 525 'Etc/Zulu' => 'Etc/UTC', 526 'FET' => 'Europe/Minsk', 527 'GB' => 'Europe/London', 528 'GB-Eire' => 'Europe/London', 529 'Greenwich' => 'Etc/GMT', 530 'Hongkong' => 'Asia/Hong_Kong', 531 'HST' => 'Pacific/Honolulu', 532 'Iceland' => 'Atlantic/Reykjavik', 533 'India Time' => 'Asia/Kolkata', 534 'Iran' => 'Asia/Tehran', 535 'Israel' => 'Asia/Jerusalem', 536 'IST' => 'Asia/Kolkata', 537 'Jamaica' => 'America/Jamaica', 538 'Japan' => 'Asia/Tokyo', 539 'Japan Standard Time' => 'Asia/Tokyo', 540 'Japan Time' => 'Asia/Tokyo', 541 'JST' => 'Asia/Tokyo', 542 'Kwajalein' => 'Pacific/Kwajalein', 543 'Libya' => 'Africa/Tripoli', 544 'MDT' => 'America/Denver', 545 'MET' => 'Europe/Paris', 546 'Mexico/BajaNorte' => 'America/Tijuana', 547 'Mexico/BajaSur' => 'America/Mazatlan', 548 'Mexico/General' => 'America/Mexico_City', 549 'MST' => 'America/Phoenix', 550 'MST7MDT' => 'America/Denver', 551 'Navajo' => 'America/Denver', 552 'NZ' => 'Pacific/Auckland', 553 'NZ-CHAT' => 'Pacific/Chatham', 554 'Pacific Time' => 'America/Los_Angeles', 555 'PDT' => 'America/Los_Angeles', 556 'Poland' => 'Europe/Warsaw', 557 'Portugal' => 'Europe/Lisbon', 558 'PRC' => 'Asia/Shanghai', 559 'PST' => 'America/Los_Angeles', 560 'PST8PDT' => 'America/Los_Angeles', 561 'ROC' => 'Asia/Taipei', 562 'ROK' => 'Asia/Seoul', 563 'Singapore' => 'Asia/Singapore', 564 'Turkey' => 'Europe/Istanbul', 565 'UCT' => 'Etc/UTC', 566 'Universal' => 'Etc/UTC', 567 'US/Alaska' => 'America/Anchorage', 568 'US/Aleutian' => 'America/Adak', 569 'US/Arizona' => 'America/Phoenix', 570 'US/Central' => 'America/Chicago', 571 'US/East-Indiana' => 'America/Indiana/Indianapolis', 572 'US/Eastern' => 'America/New_York', 573 'US/Hawaii' => 'Pacific/Honolulu', 574 'US/Indiana-Starke' => 'America/Indiana/Knox', 575 'US/Michigan' => 'America/Detroit', 576 'US/Mountain' => 'America/Denver', 577 'US/Pacific' => 'America/Los_Angeles', 578 'US/Pacific-New' => 'America/Los_Angeles', 579 'US/Samoa' => 'Pacific/Pago_Pago', 580 'W-SU' => 'Europe/Moscow', 581 'WET' => 'Europe/London', 582 'Zulu' => 'Etc/UTC', 583 584 // Some UTC variations. 585 'UTC-01' => 'Etc/GMT+1', 586 'UTC-02' => 'Etc/GMT+2', 587 'UTC-03' => 'Etc/GMT+3', 588 'UTC-04' => 'Etc/GMT+4', 589 'UTC-05' => 'Etc/GMT+5', 590 'UTC-06' => 'Etc/GMT+6', 591 'UTC-07' => 'Etc/GMT+7', 592 'UTC-08' => 'Etc/GMT+8', 593 'UTC-09' => 'Etc/GMT+9', 594 595 // Some weird GMTs. 596 'Etc/GMT+0' => 'Etc/GMT', 597 'Etc/GMT-0' => 'Etc/GMT', 598 'Etc/GMT0' => 'Etc/GMT', 599 600 // Link old timezone names with their new names. 601 'Africa/Asmera' => 'Africa/Asmara', 602 'Africa/Timbuktu' => 'Africa/Abidjan', 603 'America/Argentina/ComodRivadavia' => 'America/Argentina/Catamarca', 604 'America/Atka' => 'America/Adak', 605 'America/Buenos_Aires' => 'America/Argentina/Buenos_Aires', 606 'America/Catamarca' => 'America/Argentina/Catamarca', 607 'America/Coral_Harbour' => 'America/Atikokan', 608 'America/Cordoba' => 'America/Argentina/Cordoba', 609 'America/Ensenada' => 'America/Tijuana', 610 'America/Fort_Wayne' => 'America/Indiana/Indianapolis', 611 'America/Indianapolis' => 'America/Indiana/Indianapolis', 612 'America/Jujuy' => 'America/Argentina/Jujuy', 613 'America/Knox_IN' => 'America/Indiana/Knox', 614 'America/Louisville' => 'America/Kentucky/Louisville', 615 'America/Mendoza' => 'America/Argentina/Mendoza', 616 'America/Montreal' => 'America/Toronto', 617 'America/Porto_Acre' => 'America/Rio_Branco', 618 'America/Rosario' => 'America/Argentina/Cordoba', 619 'America/Santa_Isabel' => 'America/Tijuana', 620 'America/Shiprock' => 'America/Denver', 621 'America/Virgin' => 'America/Port_of_Spain', 622 'Antarctica/South_Pole' => 'Pacific/Auckland', 623 'Asia/Ashkhabad' => 'Asia/Ashgabat', 624 'Asia/Calcutta' => 'Asia/Kolkata', 625 'Asia/Chongqing' => 'Asia/Shanghai', 626 'Asia/Chungking' => 'Asia/Shanghai', 627 'Asia/Dacca' => 'Asia/Dhaka', 628 'Asia/Harbin' => 'Asia/Shanghai', 629 'Asia/Istanbul' => 'Europe/Istanbul', 630 'Asia/Kashgar' => 'Asia/Urumqi', 631 'Asia/Katmandu' => 'Asia/Kathmandu', 632 'Asia/Macao' => 'Asia/Macau', 633 'Asia/Rangoon' => 'Asia/Yangon', 634 'Asia/Saigon' => 'Asia/Ho_Chi_Minh', 635 'Asia/Tel_Aviv' => 'Asia/Jerusalem', 636 'Asia/Thimbu' => 'Asia/Thimphu', 637 'Asia/Ujung_Pandang' => 'Asia/Makassar', 638 'Asia/Ulan_Bator' => 'Asia/Ulaanbaatar', 639 'Atlantic/Faeroe' => 'Atlantic/Faroe', 640 'Atlantic/Jan_Mayen' => 'Europe/Oslo', 641 'Australia/Canberra' => 'Australia/Sydney', 642 'Australia/Yancowinna' => 'Australia/Broken_Hill', 643 'Europe/Belfast' => 'Europe/London', 644 'Europe/Nicosia' => 'Asia/Nicosia', 645 'Europe/Tiraspol' => 'Europe/Chisinau', 646 'Pacific/Johnston' => 'Pacific/Honolulu', 647 'Pacific/Ponape' => 'Pacific/Pohnpei', 648 'Pacific/Samoa' => 'Pacific/Pago_Pago', 649 'Pacific/Truk' => 'Pacific/Chuuk', 650 'Pacific/Yap' => 'Pacific/Chuuk', 651 ); 652 653 // Legacy GMT fallback. 654 for ($i = -12; $i <= 14; $i++) { 655 $off = abs($i); 656 if ($i < 0) { 657 $mapto = 'Etc/GMT+' . $off; 658 $utc = 'UTC-' . $off; 659 $gmt = 'GMT-' . $off; 660 } else if ($i > 0) { 661 $mapto = 'Etc/GMT-' . $off; 662 $utc = 'UTC+' . $off; 663 $gmt = 'GMT+' . $off; 664 } else { 665 $mapto = 'Etc/GMT'; 666 $utc = 'UTC'; 667 $gmt = 'GMT'; 668 } 669 if (isset(self::$bczones[$mapto])) { 670 self::$badzones[$i . ''] = $mapto; 671 self::$badzones[$i . '.0'] = $mapto; 672 self::$badzones[$utc] = $mapto; 673 self::$badzones[$gmt] = $mapto; 674 } 675 } 676 677 // Legacy Moodle half an hour offsets - pick any city nearby, ideally without DST. 678 self::$badzones['4.5'] = 'Asia/Kabul'; 679 self::$badzones['5.5'] = 'Asia/Kolkata'; 680 self::$badzones['6.5'] = 'Asia/Rangoon'; 681 self::$badzones['9.5'] = 'Australia/Darwin'; 682 683 // Remove bad zones that are elsewhere. 684 foreach (self::$bczones as $zone => $unused) { 685 if (isset(self::$badzones[$zone])) { 686 unset(self::$badzones[$zone]); 687 } 688 } 689 foreach (self::$goodzones as $zone => $unused) { 690 if (isset(self::$badzones[$zone])) { 691 unset(self::$badzones[$zone]); 692 } 693 } 694 } 695 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body