diff --git a/src/Event.php b/src/Event.php index 55cd511..0b95aca 100644 --- a/src/Event.php +++ b/src/Event.php @@ -231,7 +231,7 @@ public function toArray(array $customFields = []): array if(!empty($customFields)) { foreach ($customFields as $key => $value) { - $result[$key] = $this->{$value}; + $result[$key] = $this->{$value} ?? null; } } diff --git a/src/ICal.php b/src/ICal.php index c6f72cc..1745820 100644 --- a/src/ICal.php +++ b/src/ICal.php @@ -7,13 +7,11 @@ use DateTimeZone; use Exception; use Psr\Log\LoggerInterface; - use UnexpectedValueException; -use const PHP_VERSION_ID; - class ICal { + use TimeZoneMaps; public const DATE_TIME_FORMAT = 'Ymd\THis'; public const DATE_TIME_FORMAT_PRETTY = 'F Y H:i:s'; public const ICAL_DATE_TIME_TEMPLATE = 'TZID=%s:'; @@ -36,260 +34,7 @@ class ICal 'filterDaysBefore', 'skipRecurrence', ]; - /** - * CLDR time zones mapped to IANA time zones. - */ - private static array $cldrTimeZonesMap = [ - '(UTC-12:00) International Date Line West' => 'Etc/GMT+12', - '(UTC-11:00) Coordinated Universal Time-11' => 'Etc/GMT+11', - '(UTC-10:00) Hawaii' => 'Pacific/Honolulu', - '(UTC-09:00) Alaska' => 'America/Anchorage', - '(UTC-08:00) Pacific Time (US & Canada)' => 'America/Los_Angeles', - '(UTC-07:00) Arizona' => 'America/Phoenix', - '(UTC-07:00) Chihuahua, La Paz, Mazatlan' => 'America/Chihuahua', - '(UTC-07:00) Mountain Time (US & Canada)' => 'America/Denver', - '(UTC-06:00) Central America' => 'America/Guatemala', - '(UTC-06:00) Central Time (US & Canada)' => 'America/Chicago', - '(UTC-06:00) Guadalajara, Mexico City, Monterrey' => 'America/Mexico_City', - '(UTC-06:00) Saskatchewan' => 'America/Regina', - '(UTC-05:00) Bogota, Lima, Quito, Rio Branco' => 'America/Bogota', - '(UTC-05:00) Chetumal' => 'America/Cancun', - '(UTC-05:00) Eastern Time (US & Canada)' => 'America/New_York', - '(UTC-05:00) Indiana (East)' => 'America/Indianapolis', - '(UTC-04:00) Asuncion' => 'America/Asuncion', - '(UTC-04:00) Atlantic Time (Canada)' => 'America/Halifax', - '(UTC-04:00) Caracas' => 'America/Caracas', - '(UTC-04:00) Cuiaba' => 'America/Cuiaba', - '(UTC-04:00) Georgetown, La Paz, Manaus, San Juan' => 'America/La_Paz', - '(UTC-04:00) Santiago' => 'America/Santiago', - '(UTC-03:30) Newfoundland' => 'America/St_Johns', - '(UTC-03:00) Brasilia' => 'America/Sao_Paulo', - '(UTC-03:00) Cayenne, Fortaleza' => 'America/Cayenne', - '(UTC-03:00) City of Buenos Aires' => 'America/Buenos_Aires', - '(UTC-03:00) Greenland' => 'America/Godthab', - '(UTC-03:00) Montevideo' => 'America/Montevideo', - '(UTC-03:00) Salvador' => 'America/Bahia', - '(UTC-02:00) Coordinated Universal Time-02' => 'Etc/GMT+2', - '(UTC-01:00) Azores' => 'Atlantic/Azores', - '(UTC-01:00) Cabo Verde Is.' => 'Atlantic/Cape_Verde', - '(UTC) Coordinated Universal Time' => 'Etc/GMT', - '(UTC+00:00) Casablanca' => 'Africa/Casablanca', - '(UTC+00:00) Dublin, Edinburgh, Lisbon, London' => 'Europe/London', - '(UTC+00:00) Monrovia, Reykjavik' => 'Atlantic/Reykjavik', - '(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin', - '(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague' => 'Europe/Budapest', - '(UTC+01:00) Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris', - '(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb' => 'Europe/Warsaw', - '(UTC+01:00) West Central Africa' => 'Africa/Lagos', - '(UTC+02:00) Amman' => 'Asia/Amman', - '(UTC+02:00) Athens, Bucharest' => 'Europe/Bucharest', - '(UTC+02:00) Beirut' => 'Asia/Beirut', - '(UTC+02:00) Cairo' => 'Africa/Cairo', - '(UTC+02:00) Chisinau' => 'Europe/Chisinau', - '(UTC+02:00) Damascus' => 'Asia/Damascus', - '(UTC+02:00) Harare, Pretoria' => 'Africa/Johannesburg', - '(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius' => 'Europe/Kiev', - '(UTC+02:00) Jerusalem' => 'Asia/Jerusalem', - '(UTC+02:00) Kaliningrad' => 'Europe/Kaliningrad', - '(UTC+02:00) Tripoli' => 'Africa/Tripoli', - '(UTC+02:00) Windhoek' => 'Africa/Windhoek', - '(UTC+03:00) Baghdad' => 'Asia/Baghdad', - '(UTC+03:00) Istanbul' => 'Europe/Istanbul', - '(UTC+03:00) Kuwait, Riyadh' => 'Asia/Riyadh', - '(UTC+03:00) Minsk' => 'Europe/Minsk', - '(UTC+03:00) Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow', - '(UTC+03:00) Nairobi' => 'Africa/Nairobi', - '(UTC+03:30) Tehran' => 'Asia/Tehran', - '(UTC+04:00) Abu Dhabi, Muscat' => 'Asia/Dubai', - '(UTC+04:00) Baku' => 'Asia/Baku', - '(UTC+04:00) Izhevsk, Samara' => 'Europe/Samara', - '(UTC+04:00) Port Louis' => 'Indian/Mauritius', - '(UTC+04:00) Tbilisi' => 'Asia/Tbilisi', - '(UTC+04:00) Yerevan' => 'Asia/Yerevan', - '(UTC+04:30) Kabul' => 'Asia/Kabul', - '(UTC+05:00) Ashgabat, Tashkent' => 'Asia/Tashkent', - '(UTC+05:00) Ekaterinburg' => 'Asia/Yekaterinburg', - '(UTC+05:00) Islamabad, Karachi' => 'Asia/Karachi', - '(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi' => 'Asia/Calcutta', - '(UTC+05:30) Sri Jayawardenepura' => 'Asia/Colombo', - '(UTC+05:45) Kathmandu' => 'Asia/Katmandu', - '(UTC+06:00) Astana' => 'Asia/Almaty', - '(UTC+06:00) Dhaka' => 'Asia/Dhaka', - '(UTC+06:30) Yangon (Rangoon)' => 'Asia/Rangoon', - '(UTC+07:00) Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok', - '(UTC+07:00) Krasnoyarsk' => 'Asia/Krasnoyarsk', - '(UTC+07:00) Novosibirsk' => 'Asia/Novosibirsk', - '(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi' => 'Asia/Shanghai', - '(UTC+08:00) Irkutsk' => 'Asia/Irkutsk', - '(UTC+08:00) Kuala Lumpur, Singapore' => 'Asia/Singapore', - '(UTC+08:00) Perth' => 'Australia/Perth', - '(UTC+08:00) Taipei' => 'Asia/Taipei', - '(UTC+08:00) Ulaanbaatar' => 'Asia/Ulaanbaatar', - '(UTC+09:00) Osaka, Sapporo, Tokyo' => 'Asia/Tokyo', - '(UTC+09:00) Pyongyang' => 'Asia/Pyongyang', - '(UTC+09:00) Seoul' => 'Asia/Seoul', - '(UTC+09:00) Yakutsk' => 'Asia/Yakutsk', - '(UTC+09:30) Adelaide' => 'Australia/Adelaide', - '(UTC+09:30) Darwin' => 'Australia/Darwin', - '(UTC+10:00) Brisbane' => 'Australia/Brisbane', - '(UTC+10:00) Canberra, Melbourne, Sydney' => 'Australia/Sydney', - '(UTC+10:00) Guam, Port Moresby' => 'Pacific/Port_Moresby', - '(UTC+10:00) Hobart' => 'Australia/Hobart', - '(UTC+10:00) Vladivostok' => 'Asia/Vladivostok', - '(UTC+11:00) Chokurdakh' => 'Asia/Srednekolymsk', - '(UTC+11:00) Magadan' => 'Asia/Magadan', - '(UTC+11:00) Solomon Is., New Caledonia' => 'Pacific/Guadalcanal', - '(UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky' => 'Asia/Kamchatka', - '(UTC+12:00) Auckland, Wellington' => 'Pacific/Auckland', - '(UTC+12:00) Coordinated Universal Time+12' => 'Etc/GMT-12', - '(UTC+12:00) Fiji' => 'Pacific/Fiji', - "(UTC+13:00) Nuku'alofa" => 'Pacific/Tongatapu', - '(UTC+13:00) Samoa' => 'Pacific/Apia', - '(UTC+14:00) Kiritimati Island' => 'Pacific/Kiritimati', - ]; - /** - * Maps Windows (non-CLDR) time zone ID to IANA ID. This is pragmatic but not 100% precise as one Windows zone ID - * maps to multiple IANA IDs (one for each territory). For all practical purposes this should be good enough, though. - * - * Source: http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml - */ - private static array $windowsTimeZonesMap = [ - 'AUS Central Standard Time' => 'Australia/Darwin', - 'AUS Eastern Standard Time' => 'Australia/Sydney', - 'Afghanistan Standard Time' => 'Asia/Kabul', - 'Alaskan Standard Time' => 'America/Anchorage', - 'Aleutian Standard Time' => 'America/Adak', - 'Altai Standard Time' => 'Asia/Barnaul', - 'Arab Standard Time' => 'Asia/Riyadh', - 'Arabian Standard Time' => 'Asia/Dubai', - 'Arabic Standard Time' => 'Asia/Baghdad', - 'Argentina Standard Time' => 'America/Buenos_Aires', - 'Astrakhan Standard Time' => 'Europe/Astrakhan', - 'Atlantic Standard Time' => 'America/Halifax', - 'Aus Central W. Standard Time' => 'Australia/Eucla', - 'Azerbaijan Standard Time' => 'Asia/Baku', - 'Azores Standard Time' => 'Atlantic/Azores', - 'Bahia Standard Time' => 'America/Bahia', - 'Bangladesh Standard Time' => 'Asia/Dhaka', - 'Belarus Standard Time' => 'Europe/Minsk', - 'Bougainville Standard Time' => 'Pacific/Bougainville', - '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 Europe Standard Time' => 'Europe/Budapest', - 'Central European Standard Time' => 'Europe/Warsaw', - 'Central Pacific Standard Time' => 'Pacific/Guadalcanal', - 'Central Standard Time (Mexico)' => 'America/Mexico_City', - 'Central Standard Time' => 'America/Chicago', - 'Chatham Islands Standard Time' => 'Pacific/Chatham', - 'China Standard Time' => 'Asia/Shanghai', - 'Cuba Standard Time' => 'America/Havana', - 'Dateline Standard Time' => 'Etc/GMT+12', - 'E. Africa Standard Time' => 'Africa/Nairobi', - 'E. Australia Standard Time' => 'Australia/Brisbane', - 'E. Europe Standard Time' => 'Europe/Chisinau', - 'E. South America Standard Time' => 'America/Sao_Paulo', - 'Easter Island Standard Time' => 'Pacific/Easter', - 'Eastern Standard Time (Mexico)' => 'America/Cancun', - 'Eastern Standard Time' => 'America/New_York', - 'Egypt Standard Time' => 'Africa/Cairo', - 'Ekaterinburg Standard Time' => 'Asia/Yekaterinburg', - 'FLE Standard Time' => 'Europe/Kiev', - 'Fiji Standard Time' => 'Pacific/Fiji', - 'GMT Standard Time' => 'Europe/London', - 'GTB Standard Time' => 'Europe/Bucharest', - 'Georgian Standard Time' => 'Asia/Tbilisi', - 'Greenland Standard Time' => 'America/Godthab', - 'Greenwich Standard Time' => 'Atlantic/Reykjavik', - 'Haiti Standard Time' => 'America/Port-au-Prince', - 'Hawaiian Standard Time' => 'Pacific/Honolulu', - 'India Standard Time' => 'Asia/Calcutta', - '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', - 'Line Islands Standard Time' => 'Pacific/Kiritimati', - 'Lord Howe Standard Time' => 'Australia/Lord_Howe', - 'Magadan Standard Time' => 'Asia/Magadan', - 'Magallanes Standard Time' => 'America/Punta_Arenas', - 'Marquesas Standard Time' => 'Pacific/Marquesas', - 'Mauritius Standard Time' => 'Indian/Mauritius', - 'Middle East Standard Time' => 'Asia/Beirut', - 'Montevideo Standard Time' => 'America/Montevideo', - 'Morocco Standard Time' => 'Africa/Casablanca', - 'Mountain Standard Time (Mexico)' => 'America/Chihuahua', - 'Mountain Standard Time' => 'America/Denver', - 'Myanmar Standard Time' => 'Asia/Rangoon', - 'N. Central Asia Standard Time' => 'Asia/Novosibirsk', - 'Namibia Standard Time' => 'Africa/Windhoek', - 'Nepal Standard Time' => 'Asia/Katmandu', - 'New Zealand Standard Time' => 'Pacific/Auckland', - 'Newfoundland Standard Time' => 'America/St_Johns', - 'Norfolk Standard Time' => 'Pacific/Norfolk', - 'North Asia East Standard Time' => 'Asia/Irkutsk', - 'North Asia Standard Time' => 'Asia/Krasnoyarsk', - 'North Korea Standard Time' => 'Asia/Pyongyang', - 'Omsk Standard Time' => 'Asia/Omsk', - 'Pacific SA Standard Time' => 'America/Santiago', - 'Pacific Standard Time (Mexico)' => 'America/Tijuana', - 'Pacific Standard Time' => 'America/Los_Angeles', - 'Pakistan Standard Time' => 'Asia/Karachi', - 'Paraguay Standard Time' => 'America/Asuncion', - 'Romance Standard Time' => 'Europe/Paris', - 'Russia Time Zone 10' => 'Asia/Srednekolymsk', - 'Russia Time Zone 11' => 'Asia/Kamchatka', - 'Russia Time Zone 3' => 'Europe/Samara', - 'Russian Standard Time' => 'Europe/Moscow', - 'SA Eastern Standard Time' => 'America/Cayenne', - 'SA Pacific Standard Time' => 'America/Bogota', - 'SA Western Standard Time' => 'America/La_Paz', - 'SE Asia Standard Time' => 'Asia/Bangkok', - 'Saint Pierre Standard Time' => 'America/Miquelon', - 'Sakhalin Standard Time' => 'Asia/Sakhalin', - 'Samoa Standard Time' => 'Pacific/Apia', - 'Sao Tome Standard Time' => 'Africa/Sao_Tome', - 'Saratov Standard Time' => 'Europe/Saratov', - 'Singapore Standard Time' => 'Asia/Singapore', - 'South Africa Standard Time' => 'Africa/Johannesburg', - 'Sri Lanka Standard Time' => 'Asia/Colombo', - 'Sudan Standard Time' => 'Africa/Tripoli', - 'Syria Standard Time' => 'Asia/Damascus', - 'Taipei Standard Time' => 'Asia/Taipei', - 'Tasmania Standard Time' => 'Australia/Hobart', - 'Tocantins Standard Time' => 'America/Araguaina', - 'Tokyo Standard Time' => 'Asia/Tokyo', - 'Tomsk Standard Time' => 'Asia/Tomsk', - 'Tonga Standard Time' => 'Pacific/Tongatapu', - 'Transbaikal Standard Time' => 'Asia/Chita', - 'Turkey Standard Time' => 'Europe/Istanbul', - 'Turks And Caicos Standard Time' => 'America/Grand_Turk', - 'US Eastern Standard Time' => 'America/Indianapolis', - 'US Mountain Standard Time' => 'America/Phoenix', - 'UTC' => 'Etc/GMT', - 'UTC+12' => 'Etc/GMT-12', - 'UTC+13' => 'Etc/GMT-13', - 'UTC-02' => 'Etc/GMT+2', - 'UTC-08' => 'Etc/GMT+8', - 'UTC-09' => 'Etc/GMT+9', - 'UTC-11' => 'Etc/GMT+11', - 'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar', - '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', - 'W. Mongolia Standard Time' => 'Asia/Hovd', - 'West Asia Standard Time' => 'Asia/Tashkent', - 'West Bank Standard Time' => 'Asia/Hebron', - 'West Pacific Standard Time' => 'Pacific/Port_Moresby', - 'Yakutsk Standard Time' => 'Asia/Yakutsk', - ]; + /** * Tracks the number of alarms in the current iCal feed * @@ -417,6 +162,10 @@ class ICal * @var LoggerInterface|null $logger */ protected ?LoggerInterface $logger; + /** + * @param array $events + */ + protected array $events = []; /** * If `$filterDaysBefore` or `$filterDaysAfter` are set then the events are filtered according to the window defined * by this field and `$windowMaxTimestamp`. @@ -432,27 +181,16 @@ class ICal */ private bool $shouldFilterByWindow = false; - /** - * @param array $events - */ - protected array $events = []; - /** * Creates the ICal object * * @param array $lines * @param array $options + * @param LoggerInterface|null $logger * @throws Exception */ public function __construct(array $lines = [], array $options = [], ?LoggerInterface $logger = null) { - /** - * TODO: check and remove if redundant, or try to solve without ini_set() - */ - if (PHP_VERSION_ID < 80100) { - ini_set('auto_detect_line_endings', '1'); - } - $this->logger = $logger; @@ -1261,7 +999,7 @@ public function iCalDateToDateTime(string $icalDate): DateTime preg_match($pattern, $icalDate, $date); if (empty($date)) { - throw new \UnexpectedValueException('Invalid iCal date format.'); + throw new UnexpectedValueException('Invalid iCal date format.'); } // A Unix timestamp usually cannot represent a date prior to 1 Jan 1970. @@ -2312,6 +2050,24 @@ public function calendarTimeZone(bool $ignoreUtc = false): ?string return $timeZone; } + /** + * Returns generator of Events. + * Every event is a class with the event + * details being properties within it. + * + * @return void + */ + protected function loadEvents(): void + { + $events = $this->cal['VEVENT'] ?? []; + + if (!empty($events)) { + foreach ($events as $event) { + $this->events[] = new Event($event); + } + } + } + /** * Initialises lines from a string * @@ -2371,32 +2127,6 @@ public function hasEvents(): bool return !empty($this->events); } - /** - * Returns generator of Events. - * Every event is a class with the event - * details being properties within it. - * - * @return void - */ - protected function loadEvents(): void - { - $events = $this->cal['VEVENT'] ?? []; - - if (!empty($events)) { - foreach ($events as $event) { - $this->events[] = new Event($event); - } - } - } - - /** - * @return array - */ - public function getEvents(): array - { - return $this->events; - } - /** * Returns a sorted array of the events following a given string, * or `false` if no events exist in the range. @@ -2531,6 +2261,14 @@ public function sortEventsWithOrder(array $events, int $sortOrder = SORT_ASC): a return $extendedEvents; } + /** + * @return array + */ + public function getEvents(): array + { + return $this->events; + } + /** * @param LoggerInterface $logger * @return void diff --git a/src/TimeZoneMaps.php b/src/TimeZoneMaps.php new file mode 100644 index 0000000..f53a57b --- /dev/null +++ b/src/TimeZoneMaps.php @@ -0,0 +1,261 @@ + 'Etc/GMT+12', + '(UTC-11:00) Coordinated Universal Time-11' => 'Etc/GMT+11', + '(UTC-10:00) Hawaii' => 'Pacific/Honolulu', + '(UTC-09:00) Alaska' => 'America/Anchorage', + '(UTC-08:00) Pacific Time (US & Canada)' => 'America/Los_Angeles', + '(UTC-07:00) Arizona' => 'America/Phoenix', + '(UTC-07:00) Chihuahua, La Paz, Mazatlan' => 'America/Chihuahua', + '(UTC-07:00) Mountain Time (US & Canada)' => 'America/Denver', + '(UTC-06:00) Central America' => 'America/Guatemala', + '(UTC-06:00) Central Time (US & Canada)' => 'America/Chicago', + '(UTC-06:00) Guadalajara, Mexico City, Monterrey' => 'America/Mexico_City', + '(UTC-06:00) Saskatchewan' => 'America/Regina', + '(UTC-05:00) Bogota, Lima, Quito, Rio Branco' => 'America/Bogota', + '(UTC-05:00) Chetumal' => 'America/Cancun', + '(UTC-05:00) Eastern Time (US & Canada)' => 'America/New_York', + '(UTC-05:00) Indiana (East)' => 'America/Indianapolis', + '(UTC-04:00) Asuncion' => 'America/Asuncion', + '(UTC-04:00) Atlantic Time (Canada)' => 'America/Halifax', + '(UTC-04:00) Caracas' => 'America/Caracas', + '(UTC-04:00) Cuiaba' => 'America/Cuiaba', + '(UTC-04:00) Georgetown, La Paz, Manaus, San Juan' => 'America/La_Paz', + '(UTC-04:00) Santiago' => 'America/Santiago', + '(UTC-03:30) Newfoundland' => 'America/St_Johns', + '(UTC-03:00) Brasilia' => 'America/Sao_Paulo', + '(UTC-03:00) Cayenne, Fortaleza' => 'America/Cayenne', + '(UTC-03:00) City of Buenos Aires' => 'America/Buenos_Aires', + '(UTC-03:00) Greenland' => 'America/Godthab', + '(UTC-03:00) Montevideo' => 'America/Montevideo', + '(UTC-03:00) Salvador' => 'America/Bahia', + '(UTC-02:00) Coordinated Universal Time-02' => 'Etc/GMT+2', + '(UTC-01:00) Azores' => 'Atlantic/Azores', + '(UTC-01:00) Cabo Verde Is.' => 'Atlantic/Cape_Verde', + '(UTC) Coordinated Universal Time' => 'Etc/GMT', + '(UTC+00:00) Casablanca' => 'Africa/Casablanca', + '(UTC+00:00) Dublin, Edinburgh, Lisbon, London' => 'Europe/London', + '(UTC+00:00) Monrovia, Reykjavik' => 'Atlantic/Reykjavik', + '(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin', + '(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague' => 'Europe/Budapest', + '(UTC+01:00) Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris', + '(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb' => 'Europe/Warsaw', + '(UTC+01:00) West Central Africa' => 'Africa/Lagos', + '(UTC+02:00) Amman' => 'Asia/Amman', + '(UTC+02:00) Athens, Bucharest' => 'Europe/Bucharest', + '(UTC+02:00) Beirut' => 'Asia/Beirut', + '(UTC+02:00) Cairo' => 'Africa/Cairo', + '(UTC+02:00) Chisinau' => 'Europe/Chisinau', + '(UTC+02:00) Damascus' => 'Asia/Damascus', + '(UTC+02:00) Harare, Pretoria' => 'Africa/Johannesburg', + '(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius' => 'Europe/Kiev', + '(UTC+02:00) Jerusalem' => 'Asia/Jerusalem', + '(UTC+02:00) Kaliningrad' => 'Europe/Kaliningrad', + '(UTC+02:00) Tripoli' => 'Africa/Tripoli', + '(UTC+02:00) Windhoek' => 'Africa/Windhoek', + '(UTC+03:00) Baghdad' => 'Asia/Baghdad', + '(UTC+03:00) Istanbul' => 'Europe/Istanbul', + '(UTC+03:00) Kuwait, Riyadh' => 'Asia/Riyadh', + '(UTC+03:00) Minsk' => 'Europe/Minsk', + '(UTC+03:00) Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow', + '(UTC+03:00) Nairobi' => 'Africa/Nairobi', + '(UTC+03:30) Tehran' => 'Asia/Tehran', + '(UTC+04:00) Abu Dhabi, Muscat' => 'Asia/Dubai', + '(UTC+04:00) Baku' => 'Asia/Baku', + '(UTC+04:00) Izhevsk, Samara' => 'Europe/Samara', + '(UTC+04:00) Port Louis' => 'Indian/Mauritius', + '(UTC+04:00) Tbilisi' => 'Asia/Tbilisi', + '(UTC+04:00) Yerevan' => 'Asia/Yerevan', + '(UTC+04:30) Kabul' => 'Asia/Kabul', + '(UTC+05:00) Ashgabat, Tashkent' => 'Asia/Tashkent', + '(UTC+05:00) Ekaterinburg' => 'Asia/Yekaterinburg', + '(UTC+05:00) Islamabad, Karachi' => 'Asia/Karachi', + '(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi' => 'Asia/Calcutta', + '(UTC+05:30) Sri Jayawardenepura' => 'Asia/Colombo', + '(UTC+05:45) Kathmandu' => 'Asia/Katmandu', + '(UTC+06:00) Astana' => 'Asia/Almaty', + '(UTC+06:00) Dhaka' => 'Asia/Dhaka', + '(UTC+06:30) Yangon (Rangoon)' => 'Asia/Rangoon', + '(UTC+07:00) Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok', + '(UTC+07:00) Krasnoyarsk' => 'Asia/Krasnoyarsk', + '(UTC+07:00) Novosibirsk' => 'Asia/Novosibirsk', + '(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi' => 'Asia/Shanghai', + '(UTC+08:00) Irkutsk' => 'Asia/Irkutsk', + '(UTC+08:00) Kuala Lumpur, Singapore' => 'Asia/Singapore', + '(UTC+08:00) Perth' => 'Australia/Perth', + '(UTC+08:00) Taipei' => 'Asia/Taipei', + '(UTC+08:00) Ulaanbaatar' => 'Asia/Ulaanbaatar', + '(UTC+09:00) Osaka, Sapporo, Tokyo' => 'Asia/Tokyo', + '(UTC+09:00) Pyongyang' => 'Asia/Pyongyang', + '(UTC+09:00) Seoul' => 'Asia/Seoul', + '(UTC+09:00) Yakutsk' => 'Asia/Yakutsk', + '(UTC+09:30) Adelaide' => 'Australia/Adelaide', + '(UTC+09:30) Darwin' => 'Australia/Darwin', + '(UTC+10:00) Brisbane' => 'Australia/Brisbane', + '(UTC+10:00) Canberra, Melbourne, Sydney' => 'Australia/Sydney', + '(UTC+10:00) Guam, Port Moresby' => 'Pacific/Port_Moresby', + '(UTC+10:00) Hobart' => 'Australia/Hobart', + '(UTC+10:00) Vladivostok' => 'Asia/Vladivostok', + '(UTC+11:00) Chokurdakh' => 'Asia/Srednekolymsk', + '(UTC+11:00) Magadan' => 'Asia/Magadan', + '(UTC+11:00) Solomon Is., New Caledonia' => 'Pacific/Guadalcanal', + '(UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky' => 'Asia/Kamchatka', + '(UTC+12:00) Auckland, Wellington' => 'Pacific/Auckland', + '(UTC+12:00) Coordinated Universal Time+12' => 'Etc/GMT-12', + '(UTC+12:00) Fiji' => 'Pacific/Fiji', + "(UTC+13:00) Nuku'alofa" => 'Pacific/Tongatapu', + '(UTC+13:00) Samoa' => 'Pacific/Apia', + '(UTC+14:00) Kiritimati Island' => 'Pacific/Kiritimati', + ]; + /** + * Maps Windows (non-CLDR) time zone ID to IANA ID. This is pragmatic but not 100% precise as one Windows zone ID + * maps to multiple IANA IDs (one for each territory). For all practical purposes this should be good enough, though. + * + * Source: http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml + */ + private static array $windowsTimeZonesMap = [ + 'AUS Central Standard Time' => 'Australia/Darwin', + 'AUS Eastern Standard Time' => 'Australia/Sydney', + 'Afghanistan Standard Time' => 'Asia/Kabul', + 'Alaskan Standard Time' => 'America/Anchorage', + 'Aleutian Standard Time' => 'America/Adak', + 'Altai Standard Time' => 'Asia/Barnaul', + 'Arab Standard Time' => 'Asia/Riyadh', + 'Arabian Standard Time' => 'Asia/Dubai', + 'Arabic Standard Time' => 'Asia/Baghdad', + 'Argentina Standard Time' => 'America/Buenos_Aires', + 'Astrakhan Standard Time' => 'Europe/Astrakhan', + 'Atlantic Standard Time' => 'America/Halifax', + 'Aus Central W. Standard Time' => 'Australia/Eucla', + 'Azerbaijan Standard Time' => 'Asia/Baku', + 'Azores Standard Time' => 'Atlantic/Azores', + 'Bahia Standard Time' => 'America/Bahia', + 'Bangladesh Standard Time' => 'Asia/Dhaka', + 'Belarus Standard Time' => 'Europe/Minsk', + 'Bougainville Standard Time' => 'Pacific/Bougainville', + '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 Europe Standard Time' => 'Europe/Budapest', + 'Central European Standard Time' => 'Europe/Warsaw', + 'Central Pacific Standard Time' => 'Pacific/Guadalcanal', + 'Central Standard Time (Mexico)' => 'America/Mexico_City', + 'Central Standard Time' => 'America/Chicago', + 'Chatham Islands Standard Time' => 'Pacific/Chatham', + 'China Standard Time' => 'Asia/Shanghai', + 'Cuba Standard Time' => 'America/Havana', + 'Dateline Standard Time' => 'Etc/GMT+12', + 'E. Africa Standard Time' => 'Africa/Nairobi', + 'E. Australia Standard Time' => 'Australia/Brisbane', + 'E. Europe Standard Time' => 'Europe/Chisinau', + 'E. South America Standard Time' => 'America/Sao_Paulo', + 'Easter Island Standard Time' => 'Pacific/Easter', + 'Eastern Standard Time (Mexico)' => 'America/Cancun', + 'Eastern Standard Time' => 'America/New_York', + 'Egypt Standard Time' => 'Africa/Cairo', + 'Ekaterinburg Standard Time' => 'Asia/Yekaterinburg', + 'FLE Standard Time' => 'Europe/Kiev', + 'Fiji Standard Time' => 'Pacific/Fiji', + 'GMT Standard Time' => 'Europe/London', + 'GTB Standard Time' => 'Europe/Bucharest', + 'Georgian Standard Time' => 'Asia/Tbilisi', + 'Greenland Standard Time' => 'America/Godthab', + 'Greenwich Standard Time' => 'Atlantic/Reykjavik', + 'Haiti Standard Time' => 'America/Port-au-Prince', + 'Hawaiian Standard Time' => 'Pacific/Honolulu', + 'India Standard Time' => 'Asia/Calcutta', + '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', + 'Line Islands Standard Time' => 'Pacific/Kiritimati', + 'Lord Howe Standard Time' => 'Australia/Lord_Howe', + 'Magadan Standard Time' => 'Asia/Magadan', + 'Magallanes Standard Time' => 'America/Punta_Arenas', + 'Marquesas Standard Time' => 'Pacific/Marquesas', + 'Mauritius Standard Time' => 'Indian/Mauritius', + 'Middle East Standard Time' => 'Asia/Beirut', + 'Montevideo Standard Time' => 'America/Montevideo', + 'Morocco Standard Time' => 'Africa/Casablanca', + 'Mountain Standard Time (Mexico)' => 'America/Chihuahua', + 'Mountain Standard Time' => 'America/Denver', + 'Myanmar Standard Time' => 'Asia/Rangoon', + 'N. Central Asia Standard Time' => 'Asia/Novosibirsk', + 'Namibia Standard Time' => 'Africa/Windhoek', + 'Nepal Standard Time' => 'Asia/Katmandu', + 'New Zealand Standard Time' => 'Pacific/Auckland', + 'Newfoundland Standard Time' => 'America/St_Johns', + 'Norfolk Standard Time' => 'Pacific/Norfolk', + 'North Asia East Standard Time' => 'Asia/Irkutsk', + 'North Asia Standard Time' => 'Asia/Krasnoyarsk', + 'North Korea Standard Time' => 'Asia/Pyongyang', + 'Omsk Standard Time' => 'Asia/Omsk', + 'Pacific SA Standard Time' => 'America/Santiago', + 'Pacific Standard Time (Mexico)' => 'America/Tijuana', + 'Pacific Standard Time' => 'America/Los_Angeles', + 'Pakistan Standard Time' => 'Asia/Karachi', + 'Paraguay Standard Time' => 'America/Asuncion', + 'Romance Standard Time' => 'Europe/Paris', + 'Russia Time Zone 10' => 'Asia/Srednekolymsk', + 'Russia Time Zone 11' => 'Asia/Kamchatka', + 'Russia Time Zone 3' => 'Europe/Samara', + 'Russian Standard Time' => 'Europe/Moscow', + 'SA Eastern Standard Time' => 'America/Cayenne', + 'SA Pacific Standard Time' => 'America/Bogota', + 'SA Western Standard Time' => 'America/La_Paz', + 'SE Asia Standard Time' => 'Asia/Bangkok', + 'Saint Pierre Standard Time' => 'America/Miquelon', + 'Sakhalin Standard Time' => 'Asia/Sakhalin', + 'Samoa Standard Time' => 'Pacific/Apia', + 'Sao Tome Standard Time' => 'Africa/Sao_Tome', + 'Saratov Standard Time' => 'Europe/Saratov', + 'Singapore Standard Time' => 'Asia/Singapore', + 'South Africa Standard Time' => 'Africa/Johannesburg', + 'Sri Lanka Standard Time' => 'Asia/Colombo', + 'Sudan Standard Time' => 'Africa/Tripoli', + 'Syria Standard Time' => 'Asia/Damascus', + 'Taipei Standard Time' => 'Asia/Taipei', + 'Tasmania Standard Time' => 'Australia/Hobart', + 'Tocantins Standard Time' => 'America/Araguaina', + 'Tokyo Standard Time' => 'Asia/Tokyo', + 'Tomsk Standard Time' => 'Asia/Tomsk', + 'Tonga Standard Time' => 'Pacific/Tongatapu', + 'Transbaikal Standard Time' => 'Asia/Chita', + 'Turkey Standard Time' => 'Europe/Istanbul', + 'Turks And Caicos Standard Time' => 'America/Grand_Turk', + 'US Eastern Standard Time' => 'America/Indianapolis', + 'US Mountain Standard Time' => 'America/Phoenix', + 'UTC' => 'Etc/GMT', + 'UTC+12' => 'Etc/GMT-12', + 'UTC+13' => 'Etc/GMT-13', + 'UTC-02' => 'Etc/GMT+2', + 'UTC-08' => 'Etc/GMT+8', + 'UTC-09' => 'Etc/GMT+9', + 'UTC-11' => 'Etc/GMT+11', + 'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar', + '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', + 'W. Mongolia Standard Time' => 'Asia/Hovd', + 'West Asia Standard Time' => 'Asia/Tashkent', + 'West Bank Standard Time' => 'Asia/Hebron', + 'West Pacific Standard Time' => 'Pacific/Port_Moresby', + 'Yakutsk Standard Time' => 'Asia/Yakutsk', + ]; +}