From: Björn Schäpers <bjo...@hazardy.de> I have based this on my previous (not yet landed) patch, but it only reuses the #ifdef to include <array>. Since std::array isn't used anywhere else I thought that was the right place to put it.
I hope the formatting is okay. I've used wide strings for the Windows zone name and territory, since the Windows API returns wide strings and thus they can be compared directly. For the territory there exists a narrow string API, but internally it calls the wide string version and narrows it down. If desired I can switch to narrow strings, the conversion can be done by static_cast per character since only ASCII chars are used. -- >8 -- On Windows there is no API to get the current time zone as IANA name, instead Windows has its own zones. But there exists a mapping provided by the Unicode Consortium. This patch adds a script to convert the XML file with the mapping to a lookup table and adds a Windows code path to use that mapping. libstdc++-v3/Changelog: Implement std::chrono::current_zone() for Windows * include/bits/windows_zones-map.h: New file, contains the look up table. * scripts/gen_windows_zones_map.py: New file, generates windows_zones-map.h. * src/c++20/tzdb.cc (tzdb::current_zone): Add Windows code path. Signed-off-by: Björn Schäpers <bjo...@hazardy.de> --- libstdc++-v3/include/bits/windows_zones-map.h | 407 ++++++++++++++++++ libstdc++-v3/scripts/gen_windows_zones_map.py | 128 ++++++ libstdc++-v3/src/c++20/tzdb.cc | 102 ++++- 3 files changed, 635 insertions(+), 2 deletions(-) create mode 100644 libstdc++-v3/include/bits/windows_zones-map.h create mode 100644 libstdc++-v3/scripts/gen_windows_zones_map.py diff --git a/libstdc++-v3/include/bits/windows_zones-map.h b/libstdc++-v3/include/bits/windows_zones-map.h new file mode 100644 index 00000000000..7be736b063d --- /dev/null +++ b/libstdc++-v3/include/bits/windows_zones-map.h @@ -0,0 +1,407 @@ +// Generated by scripts/gen_windows_zones_map.py, do not edit. + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file bits/windows_zones-map.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{chrono} + */ + +#ifndef _GLIBCXX_GET_WINDOWS_ZONES_MAP +# error "This is not a public header, do not include it directly" +#endif + +struct windows_zone_map_entry +{ + wstring_view windows_name; + wstring_view territory; + string_view iana_name; +}; + +static constexpr array<windows_zone_map_entry, 361> windows_zone_map{ + { + {L"AUS Central Standard Time", L"001", "Australia/Darwin"}, + {L"AUS Eastern Standard Time", L"001", "Australia/Sydney"}, + {L"Afghanistan Standard Time", L"001", "Asia/Kabul"}, + {L"Alaskan Standard Time", L"001", "America/Anchorage"}, + {L"Aleutian Standard Time", L"001", "America/Adak"}, + {L"Altai Standard Time", L"001", "Asia/Barnaul"}, + {L"Arab Standard Time", L"001", "Asia/Riyadh"}, + {L"Arab Standard Time", L"BH", "Asia/Bahrain"}, + {L"Arab Standard Time", L"KW", "Asia/Kuwait"}, + {L"Arab Standard Time", L"QA", "Asia/Qatar"}, + {L"Arab Standard Time", L"YE", "Asia/Aden"}, + {L"Arabian Standard Time", L"001", "Asia/Dubai"}, + {L"Arabian Standard Time", L"OM", "Asia/Muscat"}, + {L"Arabian Standard Time", L"ZZ", "Etc/GMT-4"}, + {L"Arabic Standard Time", L"001", "Asia/Baghdad"}, + {L"Argentina Standard Time", L"001", "America/Buenos_Aires"}, + {L"Astrakhan Standard Time", L"001", "Europe/Astrakhan"}, + {L"Atlantic Standard Time", L"001", "America/Halifax"}, + {L"Atlantic Standard Time", L"BM", "Atlantic/Bermuda"}, + {L"Atlantic Standard Time", L"GL", "America/Thule"}, + {L"Aus Central W. Standard Time", L"001", "Australia/Eucla"}, + {L"Azerbaijan Standard Time", L"001", "Asia/Baku"}, + {L"Azores Standard Time", L"001", "Atlantic/Azores"}, + {L"Azores Standard Time", L"GL", "America/Scoresbysund"}, + {L"Bahia Standard Time", L"001", "America/Bahia"}, + {L"Bangladesh Standard Time", L"001", "Asia/Dhaka"}, + {L"Bangladesh Standard Time", L"BT", "Asia/Thimphu"}, + {L"Belarus Standard Time", L"001", "Europe/Minsk"}, + {L"Bougainville Standard Time", L"001", "Pacific/Bougainville"}, + {L"Canada Central Standard Time", L"001", "America/Regina"}, + {L"Cape Verde Standard Time", L"001", "Atlantic/Cape_Verde"}, + {L"Cape Verde Standard Time", L"ZZ", "Etc/GMT+1"}, + {L"Caucasus Standard Time", L"001", "Asia/Yerevan"}, + {L"Cen. Australia Standard Time", L"001", "Australia/Adelaide"}, + {L"Central America Standard Time", L"001", "America/Guatemala"}, + {L"Central America Standard Time", L"BZ", "America/Belize"}, + {L"Central America Standard Time", L"CR", "America/Costa_Rica"}, + {L"Central America Standard Time", L"EC", "Pacific/Galapagos"}, + {L"Central America Standard Time", L"HN", "America/Tegucigalpa"}, + {L"Central America Standard Time", L"NI", "America/Managua"}, + {L"Central America Standard Time", L"SV", "America/El_Salvador"}, + {L"Central America Standard Time", L"ZZ", "Etc/GMT+6"}, + {L"Central Asia Standard Time", L"001", "Asia/Bishkek"}, + {L"Central Asia Standard Time", L"AQ", "Antarctica/Vostok"}, + {L"Central Asia Standard Time", L"CN", "Asia/Urumqi"}, + {L"Central Asia Standard Time", L"IO", "Indian/Chagos"}, + {L"Central Asia Standard Time", L"ZZ", "Etc/GMT-6"}, + {L"Central Brazilian Standard Time", L"001", "America/Cuiaba"}, + {L"Central Europe Standard Time", L"001", "Europe/Budapest"}, + {L"Central Europe Standard Time", L"AL", "Europe/Tirane"}, + {L"Central Europe Standard Time", L"CZ", "Europe/Prague"}, + {L"Central Europe Standard Time", L"ME", "Europe/Podgorica"}, + {L"Central Europe Standard Time", L"RS", "Europe/Belgrade"}, + {L"Central Europe Standard Time", L"SI", "Europe/Ljubljana"}, + {L"Central Europe Standard Time", L"SK", "Europe/Bratislava"}, + {L"Central European Standard Time", L"001", "Europe/Warsaw"}, + {L"Central European Standard Time", L"BA", "Europe/Sarajevo"}, + {L"Central European Standard Time", L"HR", "Europe/Zagreb"}, + {L"Central European Standard Time", L"MK", "Europe/Skopje"}, + {L"Central Pacific Standard Time", L"001", "Pacific/Guadalcanal"}, + {L"Central Pacific Standard Time", L"AQ", "Antarctica/Casey"}, + {L"Central Pacific Standard Time", L"FM", "Pacific/Ponape"}, + {L"Central Pacific Standard Time", L"NC", "Pacific/Noumea"}, + {L"Central Pacific Standard Time", L"VU", "Pacific/Efate"}, + {L"Central Pacific Standard Time", L"ZZ", "Etc/GMT-11"}, + {L"Central Standard Time", L"001", "America/Chicago"}, + {L"Central Standard Time", L"CA", "America/Winnipeg"}, + {L"Central Standard Time", L"MX", "America/Matamoros"}, + {L"Central Standard Time (Mexico)", L"001", "America/Mexico_City"}, + {L"Chatham Islands Standard Time", L"001", "Pacific/Chatham"}, + {L"China Standard Time", L"001", "Asia/Shanghai"}, + {L"China Standard Time", L"HK", "Asia/Hong_Kong"}, + {L"China Standard Time", L"MO", "Asia/Macau"}, + {L"Cuba Standard Time", L"001", "America/Havana"}, + {L"Dateline Standard Time", L"001", "Etc/GMT+12"}, + {L"E. Africa Standard Time", L"001", "Africa/Nairobi"}, + {L"E. Africa Standard Time", L"AQ", "Antarctica/Syowa"}, + {L"E. Africa Standard Time", L"DJ", "Africa/Djibouti"}, + {L"E. Africa Standard Time", L"ER", "Africa/Asmera"}, + {L"E. Africa Standard Time", L"ET", "Africa/Addis_Ababa"}, + {L"E. Africa Standard Time", L"KM", "Indian/Comoro"}, + {L"E. Africa Standard Time", L"MG", "Indian/Antananarivo"}, + {L"E. Africa Standard Time", L"SO", "Africa/Mogadishu"}, + {L"E. Africa Standard Time", L"TZ", "Africa/Dar_es_Salaam"}, + {L"E. Africa Standard Time", L"UG", "Africa/Kampala"}, + {L"E. Africa Standard Time", L"YT", "Indian/Mayotte"}, + {L"E. Africa Standard Time", L"ZZ", "Etc/GMT-3"}, + {L"E. Australia Standard Time", L"001", "Australia/Brisbane"}, + {L"E. Europe Standard Time", L"001", "Europe/Chisinau"}, + {L"E. South America Standard Time", L"001", "America/Sao_Paulo"}, + {L"Easter Island Standard Time", L"001", "Pacific/Easter"}, + {L"Eastern Standard Time", L"001", "America/New_York"}, + {L"Eastern Standard Time", L"BS", "America/Nassau"}, + {L"Eastern Standard Time", L"CA", "America/Toronto"}, + {L"Eastern Standard Time (Mexico)", L"001", "America/Cancun"}, + {L"Egypt Standard Time", L"001", "Africa/Cairo"}, + {L"Ekaterinburg Standard Time", L"001", "Asia/Yekaterinburg"}, + {L"FLE Standard Time", L"001", "Europe/Kiev"}, + {L"FLE Standard Time", L"AX", "Europe/Mariehamn"}, + {L"FLE Standard Time", L"BG", "Europe/Sofia"}, + {L"FLE Standard Time", L"EE", "Europe/Tallinn"}, + {L"FLE Standard Time", L"FI", "Europe/Helsinki"}, + {L"FLE Standard Time", L"LT", "Europe/Vilnius"}, + {L"FLE Standard Time", L"LV", "Europe/Riga"}, + {L"Fiji Standard Time", L"001", "Pacific/Fiji"}, + {L"GMT Standard Time", L"001", "Europe/London"}, + {L"GMT Standard Time", L"ES", "Atlantic/Canary"}, + {L"GMT Standard Time", L"FO", "Atlantic/Faeroe"}, + {L"GMT Standard Time", L"GG", "Europe/Guernsey"}, + {L"GMT Standard Time", L"IE", "Europe/Dublin"}, + {L"GMT Standard Time", L"IM", "Europe/Isle_of_Man"}, + {L"GMT Standard Time", L"JE", "Europe/Jersey"}, + {L"GMT Standard Time", L"PT", "Europe/Lisbon"}, + {L"GTB Standard Time", L"001", "Europe/Bucharest"}, + {L"GTB Standard Time", L"CY", "Asia/Nicosia"}, + {L"GTB Standard Time", L"GR", "Europe/Athens"}, + {L"Georgian Standard Time", L"001", "Asia/Tbilisi"}, + {L"Greenland Standard Time", L"001", "America/Godthab"}, + {L"Greenwich Standard Time", L"001", "Atlantic/Reykjavik"}, + {L"Greenwich Standard Time", L"BF", "Africa/Ouagadougou"}, + {L"Greenwich Standard Time", L"CI", "Africa/Abidjan"}, + {L"Greenwich Standard Time", L"GH", "Africa/Accra"}, + {L"Greenwich Standard Time", L"GL", "America/Danmarkshavn"}, + {L"Greenwich Standard Time", L"GM", "Africa/Banjul"}, + {L"Greenwich Standard Time", L"GN", "Africa/Conakry"}, + {L"Greenwich Standard Time", L"GW", "Africa/Bissau"}, + {L"Greenwich Standard Time", L"LR", "Africa/Monrovia"}, + {L"Greenwich Standard Time", L"ML", "Africa/Bamako"}, + {L"Greenwich Standard Time", L"MR", "Africa/Nouakchott"}, + {L"Greenwich Standard Time", L"SH", "Atlantic/St_Helena"}, + {L"Greenwich Standard Time", L"SL", "Africa/Freetown"}, + {L"Greenwich Standard Time", L"SN", "Africa/Dakar"}, + {L"Greenwich Standard Time", L"TG", "Africa/Lome"}, + {L"Haiti Standard Time", L"001", "America/Port-au-Prince"}, + {L"Hawaiian Standard Time", L"001", "Pacific/Honolulu"}, + {L"Hawaiian Standard Time", L"CK", "Pacific/Rarotonga"}, + {L"Hawaiian Standard Time", L"PF", "Pacific/Tahiti"}, + {L"Hawaiian Standard Time", L"ZZ", "Etc/GMT+10"}, + {L"India Standard Time", L"001", "Asia/Calcutta"}, + {L"Iran Standard Time", L"001", "Asia/Tehran"}, + {L"Israel Standard Time", L"001", "Asia/Jerusalem"}, + {L"Jordan Standard Time", L"001", "Asia/Amman"}, + {L"Kaliningrad Standard Time", L"001", "Europe/Kaliningrad"}, + {L"Korea Standard Time", L"001", "Asia/Seoul"}, + {L"Libya Standard Time", L"001", "Africa/Tripoli"}, + {L"Line Islands Standard Time", L"001", "Pacific/Kiritimati"}, + {L"Line Islands Standard Time", L"ZZ", "Etc/GMT-14"}, + {L"Lord Howe Standard Time", L"001", "Australia/Lord_Howe"}, + {L"Magadan Standard Time", L"001", "Asia/Magadan"}, + {L"Magallanes Standard Time", L"001", "America/Punta_Arenas"}, + {L"Marquesas Standard Time", L"001", "Pacific/Marquesas"}, + {L"Mauritius Standard Time", L"001", "Indian/Mauritius"}, + {L"Mauritius Standard Time", L"RE", "Indian/Reunion"}, + {L"Mauritius Standard Time", L"SC", "Indian/Mahe"}, + {L"Middle East Standard Time", L"001", "Asia/Beirut"}, + {L"Montevideo Standard Time", L"001", "America/Montevideo"}, + {L"Morocco Standard Time", L"001", "Africa/Casablanca"}, + {L"Morocco Standard Time", L"EH", "Africa/El_Aaiun"}, + {L"Mountain Standard Time", L"001", "America/Denver"}, + {L"Mountain Standard Time", L"CA", "America/Edmonton"}, + {L"Mountain Standard Time", L"MX", "America/Ciudad_Juarez"}, + {L"Mountain Standard Time (Mexico)", L"001", "America/Mazatlan"}, + {L"Myanmar Standard Time", L"001", "Asia/Rangoon"}, + {L"Myanmar Standard Time", L"CC", "Indian/Cocos"}, + {L"N. Central Asia Standard Time", L"001", "Asia/Novosibirsk"}, + {L"Namibia Standard Time", L"001", "Africa/Windhoek"}, + {L"Nepal Standard Time", L"001", "Asia/Katmandu"}, + {L"New Zealand Standard Time", L"001", "Pacific/Auckland"}, + {L"New Zealand Standard Time", L"AQ", "Antarctica/McMurdo"}, + {L"Newfoundland Standard Time", L"001", "America/St_Johns"}, + {L"Norfolk Standard Time", L"001", "Pacific/Norfolk"}, + {L"North Asia East Standard Time", L"001", "Asia/Irkutsk"}, + {L"North Asia Standard Time", L"001", "Asia/Krasnoyarsk"}, + {L"North Korea Standard Time", L"001", "Asia/Pyongyang"}, + {L"Omsk Standard Time", L"001", "Asia/Omsk"}, + {L"Pacific SA Standard Time", L"001", "America/Santiago"}, + {L"Pacific Standard Time", L"001", "America/Los_Angeles"}, + {L"Pacific Standard Time", L"CA", "America/Vancouver"}, + {L"Pacific Standard Time (Mexico)", L"001", "America/Tijuana"}, + {L"Pakistan Standard Time", L"001", "Asia/Karachi"}, + {L"Paraguay Standard Time", L"001", "America/Asuncion"}, + {L"Qyzylorda Standard Time", L"001", "Asia/Qyzylorda"}, + {L"Romance Standard Time", L"001", "Europe/Paris"}, + {L"Romance Standard Time", L"BE", "Europe/Brussels"}, + {L"Romance Standard Time", L"DK", "Europe/Copenhagen"}, + {L"Romance Standard Time", L"ES", "Europe/Madrid"}, + {L"Russia Time Zone 10", L"001", "Asia/Srednekolymsk"}, + {L"Russia Time Zone 11", L"001", "Asia/Kamchatka"}, + {L"Russia Time Zone 3", L"001", "Europe/Samara"}, + {L"Russian Standard Time", L"001", "Europe/Moscow"}, + {L"Russian Standard Time", L"UA", "Europe/Simferopol"}, + {L"SA Eastern Standard Time", L"001", "America/Cayenne"}, + {L"SA Eastern Standard Time", L"AQ", "Antarctica/Rothera"}, + {L"SA Eastern Standard Time", L"BR", "America/Fortaleza"}, + {L"SA Eastern Standard Time", L"FK", "Atlantic/Stanley"}, + {L"SA Eastern Standard Time", L"SR", "America/Paramaribo"}, + {L"SA Eastern Standard Time", L"ZZ", "Etc/GMT+3"}, + {L"SA Pacific Standard Time", L"001", "America/Bogota"}, + {L"SA Pacific Standard Time", L"BR", "America/Rio_Branco"}, + {L"SA Pacific Standard Time", L"CA", "America/Coral_Harbour"}, + {L"SA Pacific Standard Time", L"EC", "America/Guayaquil"}, + {L"SA Pacific Standard Time", L"JM", "America/Jamaica"}, + {L"SA Pacific Standard Time", L"KY", "America/Cayman"}, + {L"SA Pacific Standard Time", L"PA", "America/Panama"}, + {L"SA Pacific Standard Time", L"PE", "America/Lima"}, + {L"SA Pacific Standard Time", L"ZZ", "Etc/GMT+5"}, + {L"SA Western Standard Time", L"001", "America/La_Paz"}, + {L"SA Western Standard Time", L"AG", "America/Antigua"}, + {L"SA Western Standard Time", L"AI", "America/Anguilla"}, + {L"SA Western Standard Time", L"AW", "America/Aruba"}, + {L"SA Western Standard Time", L"BB", "America/Barbados"}, + {L"SA Western Standard Time", L"BL", "America/St_Barthelemy"}, + {L"SA Western Standard Time", L"BQ", "America/Kralendijk"}, + {L"SA Western Standard Time", L"BR", "America/Manaus"}, + {L"SA Western Standard Time", L"CA", "America/Blanc-Sablon"}, + {L"SA Western Standard Time", L"CW", "America/Curacao"}, + {L"SA Western Standard Time", L"DM", "America/Dominica"}, + {L"SA Western Standard Time", L"DO", "America/Santo_Domingo"}, + {L"SA Western Standard Time", L"GD", "America/Grenada"}, + {L"SA Western Standard Time", L"GP", "America/Guadeloupe"}, + {L"SA Western Standard Time", L"GY", "America/Guyana"}, + {L"SA Western Standard Time", L"KN", "America/St_Kitts"}, + {L"SA Western Standard Time", L"LC", "America/St_Lucia"}, + {L"SA Western Standard Time", L"MF", "America/Marigot"}, + {L"SA Western Standard Time", L"MQ", "America/Martinique"}, + {L"SA Western Standard Time", L"MS", "America/Montserrat"}, + {L"SA Western Standard Time", L"PR", "America/Puerto_Rico"}, + {L"SA Western Standard Time", L"SX", "America/Lower_Princes"}, + {L"SA Western Standard Time", L"TT", "America/Port_of_Spain"}, + {L"SA Western Standard Time", L"VC", "America/St_Vincent"}, + {L"SA Western Standard Time", L"VG", "America/Tortola"}, + {L"SA Western Standard Time", L"VI", "America/St_Thomas"}, + {L"SA Western Standard Time", L"ZZ", "Etc/GMT+4"}, + {L"SE Asia Standard Time", L"001", "Asia/Bangkok"}, + {L"SE Asia Standard Time", L"AQ", "Antarctica/Davis"}, + {L"SE Asia Standard Time", L"CX", "Indian/Christmas"}, + {L"SE Asia Standard Time", L"ID", "Asia/Jakarta"}, + {L"SE Asia Standard Time", L"KH", "Asia/Phnom_Penh"}, + {L"SE Asia Standard Time", L"LA", "Asia/Vientiane"}, + {L"SE Asia Standard Time", L"VN", "Asia/Saigon"}, + {L"SE Asia Standard Time", L"ZZ", "Etc/GMT-7"}, + {L"Saint Pierre Standard Time", L"001", "America/Miquelon"}, + {L"Sakhalin Standard Time", L"001", "Asia/Sakhalin"}, + {L"Samoa Standard Time", L"001", "Pacific/Apia"}, + {L"Sao Tome Standard Time", L"001", "Africa/Sao_Tome"}, + {L"Saratov Standard Time", L"001", "Europe/Saratov"}, + {L"Singapore Standard Time", L"001", "Asia/Singapore"}, + {L"Singapore Standard Time", L"BN", "Asia/Brunei"}, + {L"Singapore Standard Time", L"ID", "Asia/Makassar"}, + {L"Singapore Standard Time", L"MY", "Asia/Kuala_Lumpur"}, + {L"Singapore Standard Time", L"PH", "Asia/Manila"}, + {L"Singapore Standard Time", L"ZZ", "Etc/GMT-8"}, + {L"South Africa Standard Time", L"001", "Africa/Johannesburg"}, + {L"South Africa Standard Time", L"BI", "Africa/Bujumbura"}, + {L"South Africa Standard Time", L"BW", "Africa/Gaborone"}, + {L"South Africa Standard Time", L"CD", "Africa/Lubumbashi"}, + {L"South Africa Standard Time", L"LS", "Africa/Maseru"}, + {L"South Africa Standard Time", L"MW", "Africa/Blantyre"}, + {L"South Africa Standard Time", L"MZ", "Africa/Maputo"}, + {L"South Africa Standard Time", L"RW", "Africa/Kigali"}, + {L"South Africa Standard Time", L"SZ", "Africa/Mbabane"}, + {L"South Africa Standard Time", L"ZM", "Africa/Lusaka"}, + {L"South Africa Standard Time", L"ZW", "Africa/Harare"}, + {L"South Africa Standard Time", L"ZZ", "Etc/GMT-2"}, + {L"South Sudan Standard Time", L"001", "Africa/Juba"}, + {L"Sri Lanka Standard Time", L"001", "Asia/Colombo"}, + {L"Sudan Standard Time", L"001", "Africa/Khartoum"}, + {L"Syria Standard Time", L"001", "Asia/Damascus"}, + {L"Taipei Standard Time", L"001", "Asia/Taipei"}, + {L"Tasmania Standard Time", L"001", "Australia/Hobart"}, + {L"Tocantins Standard Time", L"001", "America/Araguaina"}, + {L"Tokyo Standard Time", L"001", "Asia/Tokyo"}, + {L"Tokyo Standard Time", L"ID", "Asia/Jayapura"}, + {L"Tokyo Standard Time", L"PW", "Pacific/Palau"}, + {L"Tokyo Standard Time", L"TL", "Asia/Dili"}, + {L"Tokyo Standard Time", L"ZZ", "Etc/GMT-9"}, + {L"Tomsk Standard Time", L"001", "Asia/Tomsk"}, + {L"Tonga Standard Time", L"001", "Pacific/Tongatapu"}, + {L"Transbaikal Standard Time", L"001", "Asia/Chita"}, + {L"Turkey Standard Time", L"001", "Europe/Istanbul"}, + {L"Turks And Caicos Standard Time", L"001", "America/Grand_Turk"}, + {L"US Eastern Standard Time", L"001", "America/Indianapolis"}, + {L"US Mountain Standard Time", L"001", "America/Phoenix"}, + {L"US Mountain Standard Time", L"CA", "America/Creston"}, + {L"US Mountain Standard Time", L"MX", "America/Hermosillo"}, + {L"US Mountain Standard Time", L"ZZ", "Etc/GMT+7"}, + {L"UTC", L"001", "Etc/UTC"}, + {L"UTC+12", L"001", "Etc/GMT-12"}, + {L"UTC+12", L"KI", "Pacific/Tarawa"}, + {L"UTC+12", L"MH", "Pacific/Majuro"}, + {L"UTC+12", L"NR", "Pacific/Nauru"}, + {L"UTC+12", L"TV", "Pacific/Funafuti"}, + {L"UTC+12", L"UM", "Pacific/Wake"}, + {L"UTC+12", L"WF", "Pacific/Wallis"}, + {L"UTC+13", L"001", "Etc/GMT-13"}, + {L"UTC+13", L"KI", "Pacific/Enderbury"}, + {L"UTC+13", L"TK", "Pacific/Fakaofo"}, + {L"UTC-02", L"001", "Etc/GMT+2"}, + {L"UTC-02", L"BR", "America/Noronha"}, + {L"UTC-02", L"GS", "Atlantic/South_Georgia"}, + {L"UTC-08", L"001", "Etc/GMT+8"}, + {L"UTC-08", L"PN", "Pacific/Pitcairn"}, + {L"UTC-09", L"001", "Etc/GMT+9"}, + {L"UTC-09", L"PF", "Pacific/Gambier"}, + {L"UTC-11", L"001", "Etc/GMT+11"}, + {L"UTC-11", L"AS", "Pacific/Pago_Pago"}, + {L"UTC-11", L"NU", "Pacific/Niue"}, + {L"UTC-11", L"UM", "Pacific/Midway"}, + {L"Ulaanbaatar Standard Time", L"001", "Asia/Ulaanbaatar"}, + {L"Venezuela Standard Time", L"001", "America/Caracas"}, + {L"Vladivostok Standard Time", L"001", "Asia/Vladivostok"}, + {L"Volgograd Standard Time", L"001", "Europe/Volgograd"}, + {L"W. Australia Standard Time", L"001", "Australia/Perth"}, + {L"W. Central Africa Standard Time", L"001", "Africa/Lagos"}, + {L"W. Central Africa Standard Time", L"AO", "Africa/Luanda"}, + {L"W. Central Africa Standard Time", L"BJ", "Africa/Porto-Novo"}, + {L"W. Central Africa Standard Time", L"CD", "Africa/Kinshasa"}, + {L"W. Central Africa Standard Time", L"CF", "Africa/Bangui"}, + {L"W. Central Africa Standard Time", L"CG", "Africa/Brazzaville"}, + {L"W. Central Africa Standard Time", L"CM", "Africa/Douala"}, + {L"W. Central Africa Standard Time", L"DZ", "Africa/Algiers"}, + {L"W. Central Africa Standard Time", L"GA", "Africa/Libreville"}, + {L"W. Central Africa Standard Time", L"GQ", "Africa/Malabo"}, + {L"W. Central Africa Standard Time", L"NE", "Africa/Niamey"}, + {L"W. Central Africa Standard Time", L"TD", "Africa/Ndjamena"}, + {L"W. Central Africa Standard Time", L"TN", "Africa/Tunis"}, + {L"W. Central Africa Standard Time", L"ZZ", "Etc/GMT-1"}, + {L"W. Europe Standard Time", L"001", "Europe/Berlin"}, + {L"W. Europe Standard Time", L"AD", "Europe/Andorra"}, + {L"W. Europe Standard Time", L"AT", "Europe/Vienna"}, + {L"W. Europe Standard Time", L"CH", "Europe/Zurich"}, + {L"W. Europe Standard Time", L"GI", "Europe/Gibraltar"}, + {L"W. Europe Standard Time", L"IT", "Europe/Rome"}, + {L"W. Europe Standard Time", L"LI", "Europe/Vaduz"}, + {L"W. Europe Standard Time", L"LU", "Europe/Luxembourg"}, + {L"W. Europe Standard Time", L"MC", "Europe/Monaco"}, + {L"W. Europe Standard Time", L"MT", "Europe/Malta"}, + {L"W. Europe Standard Time", L"NL", "Europe/Amsterdam"}, + {L"W. Europe Standard Time", L"NO", "Europe/Oslo"}, + {L"W. Europe Standard Time", L"SE", "Europe/Stockholm"}, + {L"W. Europe Standard Time", L"SJ", "Arctic/Longyearbyen"}, + {L"W. Europe Standard Time", L"SM", "Europe/San_Marino"}, + {L"W. Europe Standard Time", L"VA", "Europe/Vatican"}, + {L"W. Mongolia Standard Time", L"001", "Asia/Hovd"}, + {L"West Asia Standard Time", L"001", "Asia/Tashkent"}, + {L"West Asia Standard Time", L"AQ", "Antarctica/Mawson"}, + {L"West Asia Standard Time", L"KZ", "Asia/Oral"}, + {L"West Asia Standard Time", L"MV", "Indian/Maldives"}, + {L"West Asia Standard Time", L"TF", "Indian/Kerguelen"}, + {L"West Asia Standard Time", L"TJ", "Asia/Dushanbe"}, + {L"West Asia Standard Time", L"TM", "Asia/Ashgabat"}, + {L"West Asia Standard Time", L"ZZ", "Etc/GMT-5"}, + {L"West Bank Standard Time", L"001", "Asia/Hebron"}, + {L"West Pacific Standard Time", L"001", "Pacific/Port_Moresby"}, + {L"West Pacific Standard Time", L"AQ", "Antarctica/DumontDUrville"}, + {L"West Pacific Standard Time", L"FM", "Pacific/Truk"}, + {L"West Pacific Standard Time", L"GU", "Pacific/Guam"}, + {L"West Pacific Standard Time", L"MP", "Pacific/Saipan"}, + {L"West Pacific Standard Time", L"ZZ", "Etc/GMT-10"}, + {L"Yakutsk Standard Time", L"001", "Asia/Yakutsk"}, + {L"Yukon Standard Time", L"001", "America/Whitehorse"}, + } +}; + +#undef _GLIBCXX_GET_WINDOWS_ZONES_MAP diff --git a/libstdc++-v3/scripts/gen_windows_zones_map.py b/libstdc++-v3/scripts/gen_windows_zones_map.py new file mode 100644 index 00000000000..9edfe457a5f --- /dev/null +++ b/libstdc++-v3/scripts/gen_windows_zones_map.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# +# Script to generate the map for libstdc++ std::chrono::current_zone under Windows. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# To update the Libstdc++ static data in <bits/windows_zones-map.h> download +# the latest: +# https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml +# Then run this script and save the output to +# include/bits/windows_zones-map.h + +import os +import sys +import xml.etree.ElementTree as et + +if len(sys.argv) != 2: + print("Usage: %s <windows zones xml>" % sys.argv[0], file=sys.stderr) + sys.exit(1) + +self = os.path.basename(__file__) +print("// Generated by scripts/{}, do not edit.".format(self)) +print(""" +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file bits/windows_zones-map.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{chrono} + */ +""") + +print("#ifndef _GLIBCXX_GET_WINDOWS_ZONES_MAP") +print('# error "This is not a public header, do not include it directly"') +print("#endif\n") + +class WindowsZoneMapEntry: + def __init__(self, windows, territory, iana): + self.windows = windows + self.territory = territory + self.iana = iana + + def __lt__(self, other): + if self.windows < other.windows: + return True + if self.windows > other.windows: + return False + return self.territory < other.territory + +windows_zone_map = [] + +tree = et.parse(sys.argv[1]) +xml_zone_map = tree.getroot().find("windowsZones").find("mapTimezones") + +for entry in xml_zone_map.iter("mapZone"): + iana = entry.attrib["type"] + space = iana.find(" ") + if space != -1: + iana = iana[0:space] + windows_zone_map.append(WindowsZoneMapEntry(entry.attrib["other"], entry.attrib["territory"], iana)) + +# Sort so we can use binary search on the array. +windows_zone_map.sort(); + +# Skip territories which have the same IANA zone as 001, so we can reduce the data. +last_windows_zone = "" +for entry in windows_zone_map[:]: + if entry.windows != last_windows_zone: + if entry.territory != "001": + raise ValueError("Territory \"001\" not the first one, this breaks assumptions in tzdb.cc!") + last_windows_zone = entry.windows + fallback_iana = entry.iana + else: + if entry.iana == fallback_iana: + windows_zone_map.remove(entry) + +print("""struct windows_zone_map_entry +{{ + wstring_view windows_name; + wstring_view territory; + string_view iana_name; +}}; + +static constexpr array<windows_zone_map_entry, {}> windows_zone_map{{ + {{""".format(len(windows_zone_map))) + +for entry in windows_zone_map: + print(' {{L"{}", L"{}", "{}"}},'.format(entry.windows, entry.territory, entry.iana)) + +print(""" } +};""") + +# <chrono> gives an error if this macro is left defined. +# Do this last, so that the generated output is not usable unless we reach here. +print("\n#undef _GLIBCXX_GET_WINDOWS_ZONES_MAP") diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc index 9923d14b7a7..bfbba077b92 100644 --- a/libstdc++-v3/src/c++20/tzdb.cc +++ b/libstdc++-v3/src/c++20/tzdb.cc @@ -48,6 +48,8 @@ # define WIN32_LEAN_AND_MEAN # include <windows.h> # include <psapi.h> + +# include <array> #endif #if defined __GTHREADS && ATOMIC_POINTER_LOCK_FREE == 2 @@ -1768,6 +1770,98 @@ namespace std::chrono return nullptr; // not found } + +#ifdef _GLIBCXX_HAVE_WINDOWS_H + string_view + detect_windows_zone() noexcept + { + DYNAMIC_TIME_ZONE_INFORMATION information{}; + if (GetDynamicTimeZoneInformation(&information) == TIME_ZONE_ID_INVALID) + return {}; + + constexpr SYSTEMTIME all_zero_time{}; + const wstring_view zone_name{ information.TimeZoneKeyName }; + auto equal = [](const SYSTEMTIME &lhs, const SYSTEMTIME &rhs) noexcept + { return memcmp(&lhs, &rhs, sizeof(SYSTEMTIME)) == 0; }; + // The logic is copied from icu, couldn't find the source. + // Detect if DST is disabled. + if (information.DynamicDaylightTimeDisabled + && equal(information.StandardDate, information.DaylightDate) + && ((!zone_name.empty() + && equal(information.StandardDate, all_zero_time)) + || (zone_name.empty() + && !equal(information.StandardDate, all_zero_time)))) + { + if (information.Bias == 0) + return "Etc/UTC"; + + if (information.Bias % 60 != 0) + // If the offset is not in full hours, we can't do anything really. + return {}; + + const auto raw_index = information.Bias / 60; + + // The bias added to the local time equals UTC. And GMT+X corrosponds + // to UTC-X, the sign is negated. Thus we can use the hourly bias as + // an index into an array. + if (raw_index < 0 && raw_index >= -14) + { + static array<string_view, 14> table{ + "Etc/GMT-1", "Etc/GMT-2", "Etc/GMT-3", "Etc/GMT-4", + "Etc/GMT-5", "Etc/GMT-6", "Etc/GMT-7", "Etc/GMT-8", + "Etc/GMT-9", "Etc/GMT-10", "Etc/GMT-11", "Etc/GMT-12", + "Etc/GMT-13", "Etc/GMT-14" + }; + return table[-raw_index - 1]; + } + else if (raw_index > 0 && raw_index <= 12) + { + static array<string_view, 14> table{ + "Etc/GMT+1", "Etc/GMT+2", "Etc/GMT+3", "Etc/GMT+4", + "Etc/GMT+5", "Etc/GMT+6", "Etc/GMT+7", "Etc/GMT+8", + "Etc/GMT+9", "Etc/GMT+10", "Etc/GMT+11", "Etc/GMT+12" + }; + return table[raw_index - 1]; + } + return {}; + } + +#define _GLIBCXX_GET_WINDOWS_ZONES_MAP +#include <bits/windows_zones-map.h> +#ifdef _GLIBCXX_GET_WINDOWS_ZONES_MAP +# error "Invalid windows_zones map" +#endif + + const auto zone_range + = ranges::equal_range(windows_zone_map, zone_name, {}, + &windows_zone_map_entry::windows_name); + + const auto size = ranges::size(zone_range); + if (size == 0) + // Unknown zone, we can't detect anything. + return {}; + + if (size == 1) + // Some zones have only one territory, use the quick path. + return zone_range.front().iana_name; + + const auto geo_id = GetUserGeoID(GEOCLASS_NATION); + wstring territory; + territory.resize(2); // The terminating zero is always added on top. + if (GetGeoInfoW(geo_id, GEO_ISO2, territory.data(), 3, 0) == 0) + // Couldn't detect the territory, fallback to "001", which is the first + // entry. + return zone_range.front().iana_name; + + const auto iter = ranges::lower_bound( + zone_range, territory, {}, &windows_zone_map_entry::territory); + if (iter == zone_range.end() || iter->territory != territory) + // Territory not within the the map, use "001". + return zone_range.front().iana_name; + + return iter->iana_name; + } +#endif } // namespace // Implementation of std::chrono::tzdb::locate_zone(string_view). @@ -1790,7 +1884,7 @@ namespace std::chrono { // TODO cache this function's result? -#ifndef _AIX +#if !defined(_AIX) && !defined(_GLIBCXX_HAVE_WINDOWS_H) // Repeat the preprocessor condition used by filesystem::read_symlink, // to avoid a dependency on src/c++17/fs_ops.o if it won't work anyway. #if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H) @@ -1847,7 +1941,11 @@ namespace std::chrono return tz; } } -#else +#elif defined(_GLIBCXX_HAVE_WINDOWS_H) + if (auto tz + = do_locate_zone(this->zones, this->links, detect_windows_zone())) + return tz; +#else // defined(_AIX) // AIX stores current zone in $TZ in /etc/environment but the value // is typically a POSIX time zone name, not IANA zone. // https://developer.ibm.com/articles/au-aix-posix/ -- 2.50.0