<?php
/**
* Abstract class for helping with timezones; specifically converting strings to DateTime objects.
*
* @copyright 2014 Perforce Software. All rights reserved.
* @license Please see LICENSE.txt in top-level folder of this distribution.
* @version <release>/<patch>
*/
namespace P4\Time;
class Time
{
// translation map derived from http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
// using the script collateral/scripts/timezonemap.php
// we filter for php supported zones and prefer territory 001 where possible.
protected static $tzWindowsToPhp = array(
'afghanistan standard time' => 'Asia/Kabul',
'alaskan standard time' => 'America/Anchorage',
'arabian standard time' => 'Asia/Dubai',
'arabic standard time' => 'Asia/Baghdad',
'arab standard time' => 'Asia/Riyadh',
'atlantic standard time' => 'America/Halifax',
'aus central standard time' => 'Australia/Darwin',
'aus eastern standard time' => 'Australia/Sydney',
'azerbaijan standard time' => 'Asia/Baku',
'azores standard time' => 'Atlantic/Azores',
'bahia standard time' => 'America/Bahia',
'bangladesh standard time' => 'Asia/Dhaka',
'canada central standard time' => 'America/Regina',
'cape verde standard time' => 'Atlantic/Cape_Verde',
'caucasus standard time' => 'Asia/Yerevan',
'cen. australia standard time' => 'Australia/Adelaide',
'central america standard time' => 'America/Guatemala',
'central asia standard time' => 'Asia/Almaty',
'central brazilian standard time' => 'America/Cuiaba',
'central european standard time' => 'Europe/Warsaw',
'central europe standard time' => 'Europe/Budapest',
'central pacific standard time' => 'Pacific/Guadalcanal',
'central standard time' => 'America/Chicago',
'central standard time (mexico)' => 'America/Mexico_City',
'china standard time' => 'Asia/Shanghai',
'e. africa standard time' => 'Africa/Nairobi',
'e. australia standard time' => 'Australia/Brisbane',
'e. south america standard time' => 'America/Sao_Paulo',
'eastern standard time' => 'America/New_York',
'egypt standard time' => 'Africa/Cairo',
'ekaterinburg standard time' => 'Asia/Yekaterinburg',
'fiji standard time' => 'Pacific/Fiji',
'fle standard time' => 'Europe/Kiev',
'georgian standard time' => 'Asia/Tbilisi',
'gmt standard time' => 'Europe/London',
'greenland standard time' => 'America/Godthab',
'greenwich standard time' => 'Atlantic/Reykjavik',
'gtb standard time' => 'Europe/Bucharest',
'hawaiian standard time' => 'Pacific/Honolulu',
'iran standard time' => 'Asia/Tehran',
'israel standard time' => 'Asia/Jerusalem',
'jordan standard time' => 'Asia/Amman',
'kaliningrad standard time' => 'Europe/Kaliningrad',
'korea standard time' => 'Asia/Seoul',
'libya standard time' => 'Africa/Tripoli',
'magadan standard time' => 'Asia/Magadan',
'mauritius standard time' => 'Indian/Mauritius',
'middle east standard time' => 'Asia/Beirut',
'montevideo standard time' => 'America/Montevideo',
'morocco standard time' => 'Africa/Casablanca',
'mountain standard time' => 'America/Denver',
'mountain standard time (mexico)' => 'America/Chihuahua',
'myanmar standard time' => 'Asia/Rangoon',
'n. central asia standard time' => 'Asia/Novosibirsk',
'namibia standard time' => 'Africa/Windhoek',
'newfoundland standard time' => 'America/St_Johns',
'new zealand standard time' => 'Pacific/Auckland',
'north asia east standard time' => 'Asia/Irkutsk',
'north asia standard time' => 'Asia/Krasnoyarsk',
'pacific sa standard time' => 'America/Santiago',
'pacific standard time' => 'America/Los_Angeles',
'pacific standard time (mexico)' => 'America/Santa_Isabel',
'pakistan standard time' => 'Asia/Karachi',
'paraguay standard time' => 'America/Asuncion',
'romance standard time' => 'Europe/Paris',
'russian standard time' => 'Europe/Moscow',
'sa eastern standard time' => 'America/Cayenne',
'samoa standard time' => 'Pacific/Apia',
'sa pacific standard time' => 'America/Bogota',
'sa western standard time' => 'America/La_Paz',
'se asia standard time' => 'Asia/Bangkok',
'singapore standard time' => 'Asia/Singapore',
'south africa standard time' => 'Africa/Johannesburg',
'sri lanka standard time' => 'Asia/Colombo',
'syria standard time' => 'Asia/Damascus',
'taipei standard time' => 'Asia/Taipei',
'tasmania standard time' => 'Australia/Hobart',
'tokyo standard time' => 'Asia/Tokyo',
'tonga standard time' => 'Pacific/Tongatapu',
'turkey standard time' => 'Europe/Istanbul',
'ulaanbaatar standard time' => 'Asia/Ulaanbaatar',
'us mountain standard time' => 'America/Phoenix',
'utc+12' => 'Pacific/Tarawa',
'utc-02' => 'America/Noronha',
'utc-11' => 'Pacific/Pago_Pago',
'venezuela standard time' => 'America/Caracas',
'vladivostok standard time' => 'Asia/Vladivostok',
'w. australia standard time' => 'Australia/Perth',
'w. central africa standard time' => 'Africa/Lagos',
'w. europe standard time' => 'Europe/Berlin',
'west asia standard time' => 'Asia/Tashkent',
'west pacific standard time' => 'Pacific/Port_Moresby',
'yakutsk standard time' => 'Asia/Yakutsk',
);
/**
* This method attempts to turn the passed timezone name/id into a DateTimeZone object.
* The passed zone can be a windows timezone name, timezone abbreviation or
* supported long-form PHP timezone.
*
* If we are not able to get the passed zone into a value DateTimeZone will recognize,
* an exception will be thrown.
*
* @param string $name the name or abbreviated timezone to turn into a date time zone
* @param string|int|null $offset optional - the offset in minutes e.g. "-0800" or -800
* @return \DateTimeZone an object representing the specified timezone
* @throws \Exception if the passed timezone isn't parsable
*/
public static function toDateTimeZone($name, $offset = null)
{
// if we got a windows timezone name, map it over to the PHP compatible value
if (isset(static::$tzWindowsToPhp[strtolower($name)])) {
$name = static::$tzWindowsToPhp[strtolower($name)];
}
// the 'daylight' version of windows time still map to the same olson value; check that too
if (isset(static::$tzWindowsToPhp[str_replace('daylight', 'standard', strtolower($name))])) {
$name = static::$tzWindowsToPhp[str_replace('daylight', 'standard', strtolower($name))];
}
// if we have a known abbreviation, resolve it into a full timezone name
if (array_key_exists(strtolower($name), array_change_key_case(timezone_abbreviations_list(), CASE_LOWER))) {
// if we have an offset it is expected to be in the format -430 or "+0800"
// convert this value from hours and minutes to seconds
$gmtOffset = null;
if ($offset) {
$gmtOffset = ($offset % 100) * 60;
$gmtOffset += ((int) ($offset / 100)) * 60 * 60;
}
$name = timezone_name_from_abbr($name, $gmtOffset);
}
return new \DateTimeZone($name);
}
}