用户友好的时区与PHP

I'm currently trying to figure out the best way to let the user choose timezone. I love the way Google does this when you sign up for Analytics.

Google way

1) Choose country from a drop down menu (this one is easy, people are used to find their own country in the default list of countries)

2) Show a second drop down with all timezones available in the selected country. This makes it very quick and easy to select a timezone. Especially since the user doesn't even have to care if the country only have one timezone.

The PHP way

Every recommendation (after a search on Stack overflow) is using the DateTimeZone lib. This output isn't user friendly since it's hard to find your timezone. You can't even use your keyboard since every timezone has a prefix of Europe/ Africa/ etc.

Back to my question. Is there a lib out there with a list of all countries mapped against their timezones? If not, is there an easier way to let the user choose a timezone?

There's http://php.net/manual/en/datetimezone.listidentifiers.php ; and it should be easy to strip out the "continent/" from each element of the list. One of the examples on the page even has this in code.

I found a unicode document, which combines time-zones for those countries where daylight savings time works the same way. This list reduces the number of choices to 100. I used this list to create a MySQL table containing all these entries.

You can then easily create a drop-down list from this. Using the PHP function date_default_timezone_set() with php_code will then set the timezone correctly.

Here is the MySQL table structure.

INSERT INTO `timezone` (`timezone_id`, `php_code`, `timezone_description`) VALUES
(1, 'Etc/GMT+12', '(UTC-12:00) International Date Line West'),
(2, 'Etc/GMT+11', '(UTC-11:00) Coordinated Universal Time-11'),
(3, 'Etc/GMT+10', '(UTC-10:00) Hawaii'),
(4, 'America/Anchorage', '(UTC-09:00) Alaska'),
(5, 'America/Santa_Isabel', '(UTC-08:00) Baja California'),
(6, 'PST8PDT', '(UTC-08:00) Pacific Time (US & Canada)'),
(7, 'Etc/GMT+7', '(UTC-07:00) Arizona'),
(8, 'America/Chihuahua', '(UTC-07:00) Chihuahua, La Paz, Mazatlan'),
(9, 'MST7MDT', '(UTC-07:00) Mountain Time (US & Canada)'),
(10, 'Etc/GMT+6', '(UTC-06:00) Central America'),
(11, 'CST6CDT', '(UTC-06:00) Central Time (US & Canada)'),
(12, 'America/Mexico_City', '(UTC-06:00) Guadalajara, Mexico City, Monterrey'),
(13, 'America/Regina', '(UTC-06:00) Saskatchewan'),
(14, 'Etc/GMT+5', '(UTC-05:00) Bogota, Lima, Quito'),
(15, 'EST5EDT', '(UTC-05:00) Eastern Time (US & Canada)'),
(16, 'America/Indianapolis', '(UTC-05:00) Indiana (East)'),
(17, 'America/Caracas', '(UTC-04:30) Caracas'),
(18, 'America/Asuncion', '(UTC-04:00) Asuncion'),
(19, 'America/Halifax', '(UTC-04:00) Atlantic Time (Canada)'),
(20, 'America/Cuiaba', '(UTC-04:00) Cuiaba'),
(21, 'Etc/GMT+4', '(UTC-04:00) Georgetown, La Paz, Manaus, San Juan'),
(22, 'America/Santiago', '(UTC-04:00) Santiago'),
(23, 'America/St_Johns', '(UTC-03:30) Newfoundland'),
(24, 'America/Sao_Paulo', '(UTC-03:00) Brasilia'),
(25, 'America/Buenos_Aires', '(UTC-03:00) Buenos Aires'),
(26, 'Etc/GMT+3', '(UTC-03:00) Cayenne, Fortaleza'),
(27, 'America/Godthab', '(UTC-03:00) Greenland'),
(28, 'America/Montevideo', '(UTC-03:00) Montevideo'),
(29, 'America/Bahia', '(UTC-03:00) Salvador'),
(30, 'Etc/GMT+2', '(UTC-02:00) Coordinated Universal Time-02'),
(31, 'Etc/GMT+2', '(UTC-02:00) Mid-Atlantic'),
(32, 'Atlantic/Azore', '(UTC-01:00) Azores'),
(33, 'Etc/GMT+1', '(UTC-01:00) Cape Verde Is.'),
(34, 'Africa/Casablanca', '(UTC) Casablanca'),
(35, 'Etc/GMT', '(UTC) Coordinated Universal Time'),
(36, 'Europe/London', '(UTC) Dublin, Edinburgh, Lisbon, London'),
(37, 'Atlantic/Reykjavik', '(UTC) Monrovia, Reykjavik'),
(38, 'Europe/Berlin', '(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna'),
(39, 'Europe/Budapest', '(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague'),
(40, 'Europe/Paris', '(UTC+01:00) Brussels, Copenhagen, Madrid, Paris'),
(41, 'Europe/Warsaw', '(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb'),
(42, 'Etc/GMT-1', '(UTC+01:00) West Central Africa'),
(43, 'Africa/Windhoek', '(UTC+01:00) Windhoek'),
(44, 'Europe/Bucharest', '(UTC+02:00) Athens, Bucharest'),
(45, 'Asia/Beirut', '(UTC+02:00) Beirut'),
(46, 'Africa/Cairo', '(UTC+02:00) Cairo'),
(47, 'Asia/Damascus', '(UTC+02:00) Damascus'),
(48, 'Asia/Nicosia', '(UTC+02:00) E. Europe'),
(49, 'Africa/Johannesburg', '(UTC+02:00) Harare, Pretoria'),
(50, 'Europe/Kiev', '(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius'),
(51, 'Europe/Istanbul', '(UTC+02:00) Istanbul'),
(52, 'Asia/Jerusalem', '(UTC+02:00) Jerusalem'),
(53, 'Asia/Amman', '(UTC+03:00) Amman'),
(54, 'Asia/Baghdad', '(UTC+03:00) Baghdad'),
(55, 'Europe/Kaliningrad', '(UTC+03:00) Kaliningrad, Minsk'),
(56, 'Asia/Riyadh', '(UTC+03:00) Kuwait, Riyadh'),
(57, 'Africa/Nairobi', '(UTC+03:00) Nairobi'),
(58, 'Asia/Tehran', '(UTC+03:30) Tehran'),
(59, 'Asia/Dubai', '(UTC+04:00) Abu Dhabi, Muscat'),
(60, 'Asia/Baku', '(UTC+04:00) Baku'),
(61, 'Europe/Moscow', '(UTC+04:00) Moscow, St. Petersburg, Volgograd'),
(62, 'Indian/Mauritius', '(UTC+04:00) Port Louis'),
(63, 'Asia/Tbilisi', '(UTC+04:00) Tbilisi'),
(64, 'Asia/Yerevan', '(UTC+04:00) Yerevan'),
(65, 'Asia/Kabul', '(UTC+04:30) Kabul'),
(66, 'Asia/Karachi', '(UTC+05:00) Islamabad, Karachi'),
(67, 'Etc/GMT-5', '(UTC+05:00) Tashkent'),
(68, 'Asia/Calcutta', '(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi'),
(69, 'Asia/Colombo', '(UTC+05:30) Sri Jayawardenepura'),
(70, 'Asia/Katmandu', '(UTC+05:45) Kathmandu'),
(71, 'Etc/GMT-6', '(UTC+06:00) Astana'),
(72, 'Asia/Dhaka', '(UTC+06:00) Dhaka'),
(73, 'Asia/Yekaterinburg', '(UTC+06:00) Ekaterinburg'),
(74, 'Asia/Rangoon', '(UTC+06:30) Yangon (Rangoon)'),
(75, 'Asia/Bangkok', '(UTC+07:00) Bangkok, Hanoi, Jakarta'),
(76, 'Asia/Novosibirsk', '(UTC+07:00) Novosibirsk'),
(77, 'Asia/Shanghai', '(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi'),
(78, 'Asia/Krasnoyarsk', '(UTC+08:00) Krasnoyarsk'),
(79, 'Etc/GMT-8', '(UTC+08:00) Kuala Lumpur, Singapore'),
(80, 'Australia/Perth', '(UTC+08:00) Perth'),
(81, 'Asia/Taipei', '(UTC+08:00) Taipei'),
(82, 'Asia/Ulaanbaatar', '(UTC+08:00) Ulaanbaatar'),
(83, 'Asia/Irkutsk', '(UTC+09:00) Irkutsk'),
(84, 'Etc/GMT-9', '(UTC+09:00) Osaka, Sapporo, Tokyo'),
(85, 'Asia/Seoul', '(UTC+09:00) Seoul'),
(86, 'Australia/Adelaide', '(UTC+09:30) Adelaide'),
(87, 'Australia/Darwin', '(UTC+09:30) Darwin'),
(88, 'Australia/Brisbane', '(UTC+10:00) Brisbane'),
(89, 'Australia/Sydney', '(UTC+10:00) Canberra, Melbourne, Sydney'),
(90, 'Etc/GMT-10', '(UTC+10:00) Guam, Port Moresby'),
(91, 'Australia/Hobart', '(UTC+10:00) Hobart'),
(92, 'Asia/Yakutsk', '(UTC+10:00) Yakutsk'),
(93, 'Etc/GMT-11', '(UTC+11:00) Solomon Is., New Caledonia'),
(94, 'Asia/Vladivostok', '(UTC+11:00) Vladivostok'),
(95, 'Pacific/Auckland', '(UTC+12:00) Auckland, Wellington'),
(96, 'Etc/GMT-12', '(UTC+12:00) Coordinated Universal Time+12'),
(97, 'Pacific/Fiji', '(UTC+12:00) Fiji'),
(98, 'Asia/Magadan', '(UTC+12:00) Magadan'),
(99, 'Etc/GMT-13', '(UTC+13:00) Nuku''alofa'),
(100, 'Pacific/Apia', '(UTC+13:00) Samoa');