forked from HowardHinnant/date
Initial Win32 support.
This library now compiles on Windows but requires VS2015 for Windows. VS2013 may work but this has not been tested yet. Requires NOMINMAX to be defined to avoid clashes with the Windows.h headers and the C++ stl and this libraries Date max functions. Also known to work equivalently with recent g++ and mingw combinations but -std=C++14 flag should be set. C++14 restrictions may be relaxed later. Patches welcome! g++ 5.1 was tested. It may work with other version but that hasn't been tried. Mac OS and Linux systems are known to compile with -std=c++11 current_timezone and locate_zone will return iana names not windows time zone names. This is expected and as designed.
This commit is contained in:
449
TimeZoneMappings.csv
Normal file
449
TimeZoneMappings.csv
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
"AUS Central Standard Time","001","Australia/Darwin"
|
||||||
|
"AUS Central Standard Time","AU","Australia/Darwin"
|
||||||
|
"AUS Eastern Standard Time","001","Australia/Sydney"
|
||||||
|
"AUS Eastern Standard Time","AU","Australia/Sydney Australia/Melbourne"
|
||||||
|
"Afghanistan Standard Time","001","Asia/Kabul"
|
||||||
|
"Afghanistan Standard Time","AF","Asia/Kabul"
|
||||||
|
"Alaskan Standard Time","001","America/Anchorage"
|
||||||
|
"Alaskan Standard Time","US","America/Anchorage America/Juneau America/Nome America/Sitka America/Yakutat"
|
||||||
|
"Arab Standard Time","001","Asia/Riyadh"
|
||||||
|
"Arab Standard Time","BH","Asia/Bahrain"
|
||||||
|
"Arab Standard Time","KW","Asia/Kuwait"
|
||||||
|
"Arab Standard Time","QA","Asia/Qatar"
|
||||||
|
"Arab Standard Time","SA","Asia/Riyadh"
|
||||||
|
"Arab Standard Time","YE","Asia/Aden"
|
||||||
|
"Arabian Standard Time","001","Asia/Dubai"
|
||||||
|
"Arabian Standard Time","AE","Asia/Dubai"
|
||||||
|
"Arabian Standard Time","OM","Asia/Muscat"
|
||||||
|
"Arabian Standard Time","ZZ","Etc/GMT-4"
|
||||||
|
"Arabic Standard Time","001","Asia/Baghdad"
|
||||||
|
"Arabic Standard Time","IQ","Asia/Baghdad"
|
||||||
|
"Argentina Standard Time","001","America/Buenos_Aires"
|
||||||
|
"Argentina Standard Time","AR","America/Buenos_Aires America/Argentina/La_Rioja America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Catamarca America/Cordoba America/Jujuy America/Mendoza"
|
||||||
|
"Atlantic Standard Time","001","America/Halifax"
|
||||||
|
"Atlantic Standard Time","BM","Atlantic/Bermuda"
|
||||||
|
"Atlantic Standard Time","CA","America/Halifax America/Glace_Bay America/Goose_Bay America/Moncton"
|
||||||
|
"Atlantic Standard Time","GL","America/Thule"
|
||||||
|
"Azerbaijan Standard Time","001","Asia/Baku"
|
||||||
|
"Azerbaijan Standard Time","AZ","Asia/Baku"
|
||||||
|
"Azores Standard Time","001","Atlantic/Azores"
|
||||||
|
"Azores Standard Time","GL","America/Scoresbysund"
|
||||||
|
"Azores Standard Time","PT","Atlantic/Azores"
|
||||||
|
"Bahia Standard Time","001","America/Bahia"
|
||||||
|
"Bahia Standard Time","BR","America/Bahia"
|
||||||
|
"Bangladesh Standard Time","001","Asia/Dhaka"
|
||||||
|
"Bangladesh Standard Time","BD","Asia/Dhaka"
|
||||||
|
"Bangladesh Standard Time","BT","Asia/Thimphu"
|
||||||
|
"Belarus Standard Time","001","Europe/Minsk"
|
||||||
|
"Belarus Standard Time","BY","Europe/Minsk"
|
||||||
|
"Canada Central Standard Time","001","America/Regina"
|
||||||
|
"Canada Central Standard Time","CA","America/Regina America/Swift_Current"
|
||||||
|
"Cape Verde Standard Time","001","Atlantic/Cape_Verde"
|
||||||
|
"Cape Verde Standard Time","CV","Atlantic/Cape_Verde"
|
||||||
|
"Cape Verde Standard Time","ZZ","Etc/GMT+1"
|
||||||
|
"Caucasus Standard Time","001","Asia/Yerevan"
|
||||||
|
"Caucasus Standard Time","AM","Asia/Yerevan"
|
||||||
|
"Cen. Australia Standard Time","001","Australia/Adelaide"
|
||||||
|
"Cen. Australia Standard Time","AU","Australia/Adelaide Australia/Broken_Hill"
|
||||||
|
"Central America Standard Time","001","America/Guatemala"
|
||||||
|
"Central America Standard Time","BZ","America/Belize"
|
||||||
|
"Central America Standard Time","CR","America/Costa_Rica"
|
||||||
|
"Central America Standard Time","EC","Pacific/Galapagos"
|
||||||
|
"Central America Standard Time","GT","America/Guatemala"
|
||||||
|
"Central America Standard Time","HN","America/Tegucigalpa"
|
||||||
|
"Central America Standard Time","NI","America/Managua"
|
||||||
|
"Central America Standard Time","SV","America/El_Salvador"
|
||||||
|
"Central America Standard Time","ZZ","Etc/GMT+6"
|
||||||
|
"Central Asia Standard Time","001","Asia/Almaty"
|
||||||
|
"Central Asia Standard Time","AQ","Antarctica/Vostok"
|
||||||
|
"Central Asia Standard Time","CN","Asia/Urumqi"
|
||||||
|
"Central Asia Standard Time","IO","Indian/Chagos"
|
||||||
|
"Central Asia Standard Time","KG","Asia/Bishkek"
|
||||||
|
"Central Asia Standard Time","KZ","Asia/Almaty Asia/Qyzylorda"
|
||||||
|
"Central Asia Standard Time","ZZ","Etc/GMT-6"
|
||||||
|
"Central Brazilian Standard Time","001","America/Cuiaba"
|
||||||
|
"Central Brazilian Standard Time","BR","America/Cuiaba America/Campo_Grande"
|
||||||
|
"Central Europe Standard Time","001","Europe/Budapest"
|
||||||
|
"Central Europe Standard Time","AL","Europe/Tirane"
|
||||||
|
"Central Europe Standard Time","CZ","Europe/Prague"
|
||||||
|
"Central Europe Standard Time","HU","Europe/Budapest"
|
||||||
|
"Central Europe Standard Time","ME","Europe/Podgorica"
|
||||||
|
"Central Europe Standard Time","RS","Europe/Belgrade"
|
||||||
|
"Central Europe Standard Time","SI","Europe/Ljubljana"
|
||||||
|
"Central Europe Standard Time","SK","Europe/Bratislava"
|
||||||
|
"Central European Standard Time","001","Europe/Warsaw"
|
||||||
|
"Central European Standard Time","BA","Europe/Sarajevo"
|
||||||
|
"Central European Standard Time","HR","Europe/Zagreb"
|
||||||
|
"Central European Standard Time","MK","Europe/Skopje"
|
||||||
|
"Central European Standard Time","PL","Europe/Warsaw"
|
||||||
|
"Central Pacific Standard Time","001","Pacific/Guadalcanal"
|
||||||
|
"Central Pacific Standard Time","AU","Antarctica/Macquarie"
|
||||||
|
"Central Pacific Standard Time","FM","Pacific/Ponape Pacific/Kosrae"
|
||||||
|
"Central Pacific Standard Time","NC","Pacific/Noumea"
|
||||||
|
"Central Pacific Standard Time","PG","Pacific/Bougainville"
|
||||||
|
"Central Pacific Standard Time","SB","Pacific/Guadalcanal"
|
||||||
|
"Central Pacific Standard Time","VU","Pacific/Efate"
|
||||||
|
"Central Pacific Standard Time","ZZ","Etc/GMT-11"
|
||||||
|
"Central Standard Time","001","America/Chicago"
|
||||||
|
"Central Standard Time","CA","America/Winnipeg America/Rainy_River America/Rankin_Inlet America/Resolute"
|
||||||
|
"Central Standard Time","MX","America/Matamoros"
|
||||||
|
"Central Standard Time","US","America/Chicago America/Indiana/Knox America/Indiana/Tell_City America/Menominee America/North_Dakota/Beulah America/North_Dakota/Center America/North_Dakota/New_Salem"
|
||||||
|
"Central Standard Time","ZZ","CST6CDT"
|
||||||
|
"Central Standard Time (Mexico)","001","America/Mexico_City"
|
||||||
|
"Central Standard Time (Mexico)","MX","America/Mexico_City America/Bahia_Banderas America/Merida America/Monterrey"
|
||||||
|
"China Standard Time","001","Asia/Shanghai"
|
||||||
|
"China Standard Time","CN","Asia/Shanghai"
|
||||||
|
"China Standard Time","HK","Asia/Hong_Kong"
|
||||||
|
"China Standard Time","MO","Asia/Macau"
|
||||||
|
"Dateline Standard Time","001","Etc/GMT+12"
|
||||||
|
"Dateline Standard Time","ZZ","Etc/GMT+12"
|
||||||
|
"E. Africa Standard Time","001","Africa/Nairobi"
|
||||||
|
"E. Africa Standard Time","AQ","Antarctica/Syowa"
|
||||||
|
"E. Africa Standard Time","DJ","Africa/Djibouti"
|
||||||
|
"E. Africa Standard Time","ER","Africa/Asmera"
|
||||||
|
"E. Africa Standard Time","ET","Africa/Addis_Ababa"
|
||||||
|
"E. Africa Standard Time","KE","Africa/Nairobi"
|
||||||
|
"E. Africa Standard Time","KM","Indian/Comoro"
|
||||||
|
"E. Africa Standard Time","MG","Indian/Antananarivo"
|
||||||
|
"E. Africa Standard Time","SD","Africa/Khartoum"
|
||||||
|
"E. Africa Standard Time","SO","Africa/Mogadishu"
|
||||||
|
"E. Africa Standard Time","SS","Africa/Juba"
|
||||||
|
"E. Africa Standard Time","TZ","Africa/Dar_es_Salaam"
|
||||||
|
"E. Africa Standard Time","UG","Africa/Kampala"
|
||||||
|
"E. Africa Standard Time","YT","Indian/Mayotte"
|
||||||
|
"E. Africa Standard Time","ZZ","Etc/GMT-3"
|
||||||
|
"E. Australia Standard Time","001","Australia/Brisbane"
|
||||||
|
"E. Australia Standard Time","AU","Australia/Brisbane Australia/Lindeman"
|
||||||
|
"E. South America Standard Time","001","America/Sao_Paulo"
|
||||||
|
"E. South America Standard Time","BR","America/Sao_Paulo"
|
||||||
|
"Eastern Standard Time","001","America/New_York"
|
||||||
|
"Eastern Standard Time","BS","America/Nassau"
|
||||||
|
"Eastern Standard Time","CA","America/Toronto America/Iqaluit America/Montreal America/Nipigon America/Pangnirtung America/Thunder_Bay"
|
||||||
|
"Eastern Standard Time","CU","America/Havana"
|
||||||
|
"Eastern Standard Time","HT","America/Port-au-Prince"
|
||||||
|
"Eastern Standard Time","US","America/New_York America/Detroit America/Indiana/Petersburg America/Indiana/Vincennes America/Indiana/Winamac America/Kentucky/Monticello America/Louisville"
|
||||||
|
"Eastern Standard Time","ZZ","EST5EDT"
|
||||||
|
"Eastern Standard Time (Mexico)","001","America/Cancun"
|
||||||
|
"Eastern Standard Time (Mexico)","MX","America/Cancun"
|
||||||
|
"Egypt Standard Time","001","Africa/Cairo"
|
||||||
|
"Egypt Standard Time","EG","Africa/Cairo"
|
||||||
|
"Ekaterinburg Standard Time","001","Asia/Yekaterinburg"
|
||||||
|
"Ekaterinburg Standard Time","RU","Asia/Yekaterinburg"
|
||||||
|
"FLE Standard Time","001","Europe/Kiev"
|
||||||
|
"FLE Standard Time","AX","Europe/Mariehamn"
|
||||||
|
"FLE Standard Time","BG","Europe/Sofia"
|
||||||
|
"FLE Standard Time","EE","Europe/Tallinn"
|
||||||
|
"FLE Standard Time","FI","Europe/Helsinki"
|
||||||
|
"FLE Standard Time","LT","Europe/Vilnius"
|
||||||
|
"FLE Standard Time","LV","Europe/Riga"
|
||||||
|
"FLE Standard Time","UA","Europe/Kiev Europe/Uzhgorod Europe/Zaporozhye"
|
||||||
|
"Fiji Standard Time","001","Pacific/Fiji"
|
||||||
|
"Fiji Standard Time","FJ","Pacific/Fiji"
|
||||||
|
"GMT Standard Time","001","Europe/London"
|
||||||
|
"GMT Standard Time","ES","Atlantic/Canary"
|
||||||
|
"GMT Standard Time","FO","Atlantic/Faeroe"
|
||||||
|
"GMT Standard Time","GB","Europe/London"
|
||||||
|
"GMT Standard Time","GG","Europe/Guernsey"
|
||||||
|
"GMT Standard Time","IE","Europe/Dublin"
|
||||||
|
"GMT Standard Time","IM","Europe/Isle_of_Man"
|
||||||
|
"GMT Standard Time","JE","Europe/Jersey"
|
||||||
|
"GMT Standard Time","PT","Europe/Lisbon Atlantic/Madeira"
|
||||||
|
"GTB Standard Time","001","Europe/Bucharest"
|
||||||
|
"GTB Standard Time","CY","Asia/Nicosia"
|
||||||
|
"GTB Standard Time","GR","Europe/Athens"
|
||||||
|
"GTB Standard Time","MD","Europe/Chisinau"
|
||||||
|
"GTB Standard Time","RO","Europe/Bucharest"
|
||||||
|
"Georgian Standard Time","001","Asia/Tbilisi"
|
||||||
|
"Georgian Standard Time","GE","Asia/Tbilisi"
|
||||||
|
"Greenland Standard Time","001","America/Godthab"
|
||||||
|
"Greenland Standard Time","GL","America/Godthab"
|
||||||
|
"Greenwich Standard Time","001","Atlantic/Reykjavik"
|
||||||
|
"Greenwich Standard Time","BF","Africa/Ouagadougou"
|
||||||
|
"Greenwich Standard Time","CI","Africa/Abidjan"
|
||||||
|
"Greenwich Standard Time","GH","Africa/Accra"
|
||||||
|
"Greenwich Standard Time","GM","Africa/Banjul"
|
||||||
|
"Greenwich Standard Time","GN","Africa/Conakry"
|
||||||
|
"Greenwich Standard Time","GW","Africa/Bissau"
|
||||||
|
"Greenwich Standard Time","IS","Atlantic/Reykjavik"
|
||||||
|
"Greenwich Standard Time","LR","Africa/Monrovia"
|
||||||
|
"Greenwich Standard Time","ML","Africa/Bamako"
|
||||||
|
"Greenwich Standard Time","MR","Africa/Nouakchott"
|
||||||
|
"Greenwich Standard Time","SH","Atlantic/St_Helena"
|
||||||
|
"Greenwich Standard Time","SL","Africa/Freetown"
|
||||||
|
"Greenwich Standard Time","SN","Africa/Dakar"
|
||||||
|
"Greenwich Standard Time","ST","Africa/Sao_Tome"
|
||||||
|
"Greenwich Standard Time","TG","Africa/Lome"
|
||||||
|
"Hawaiian Standard Time","001","Pacific/Honolulu"
|
||||||
|
"Hawaiian Standard Time","CK","Pacific/Rarotonga"
|
||||||
|
"Hawaiian Standard Time","PF","Pacific/Tahiti"
|
||||||
|
"Hawaiian Standard Time","UM","Pacific/Johnston"
|
||||||
|
"Hawaiian Standard Time","US","Pacific/Honolulu"
|
||||||
|
"Hawaiian Standard Time","ZZ","Etc/GMT+10"
|
||||||
|
"India Standard Time","001","Asia/Calcutta"
|
||||||
|
"India Standard Time","IN","Asia/Calcutta"
|
||||||
|
"Iran Standard Time","001","Asia/Tehran"
|
||||||
|
"Iran Standard Time","IR","Asia/Tehran"
|
||||||
|
"Israel Standard Time","001","Asia/Jerusalem"
|
||||||
|
"Israel Standard Time","IL","Asia/Jerusalem"
|
||||||
|
"Jordan Standard Time","001","Asia/Amman"
|
||||||
|
"Jordan Standard Time","JO","Asia/Amman"
|
||||||
|
"Kaliningrad Standard Time","001","Europe/Kaliningrad"
|
||||||
|
"Kaliningrad Standard Time","RU","Europe/Kaliningrad"
|
||||||
|
"Korea Standard Time","001","Asia/Seoul"
|
||||||
|
"Korea Standard Time","KP","Asia/Pyongyang"
|
||||||
|
"Korea Standard Time","KR","Asia/Seoul"
|
||||||
|
"Libya Standard Time","001","Africa/Tripoli"
|
||||||
|
"Libya Standard Time","LY","Africa/Tripoli"
|
||||||
|
"Line Islands Standard Time","001","Pacific/Kiritimati"
|
||||||
|
"Line Islands Standard Time","KI","Pacific/Kiritimati"
|
||||||
|
"Line Islands Standard Time","ZZ","Etc/GMT-14"
|
||||||
|
"Magadan Standard Time","001","Asia/Magadan"
|
||||||
|
"Magadan Standard Time","RU","Asia/Magadan"
|
||||||
|
"Mauritius Standard Time","001","Indian/Mauritius"
|
||||||
|
"Mauritius Standard Time","MU","Indian/Mauritius"
|
||||||
|
"Mauritius Standard Time","RE","Indian/Reunion"
|
||||||
|
"Mauritius Standard Time","SC","Indian/Mahe"
|
||||||
|
"Middle East Standard Time","001","Asia/Beirut"
|
||||||
|
"Middle East Standard Time","LB","Asia/Beirut"
|
||||||
|
"Montevideo Standard Time","001","America/Montevideo"
|
||||||
|
"Montevideo Standard Time","UY","America/Montevideo"
|
||||||
|
"Morocco Standard Time","001","Africa/Casablanca"
|
||||||
|
"Morocco Standard Time","EH","Africa/El_Aaiun"
|
||||||
|
"Morocco Standard Time","MA","Africa/Casablanca"
|
||||||
|
"Mountain Standard Time","001","America/Denver"
|
||||||
|
"Mountain Standard Time","CA","America/Edmonton America/Cambridge_Bay America/Inuvik America/Yellowknife"
|
||||||
|
"Mountain Standard Time","MX","America/Ojinaga"
|
||||||
|
"Mountain Standard Time","US","America/Denver America/Boise"
|
||||||
|
"Mountain Standard Time","ZZ","MST7MDT"
|
||||||
|
"Mountain Standard Time (Mexico)","001","America/Chihuahua"
|
||||||
|
"Mountain Standard Time (Mexico)","MX","America/Chihuahua America/Mazatlan"
|
||||||
|
"Myanmar Standard Time","001","Asia/Rangoon"
|
||||||
|
"Myanmar Standard Time","CC","Indian/Cocos"
|
||||||
|
"Myanmar Standard Time","MM","Asia/Rangoon"
|
||||||
|
"N. Central Asia Standard Time","001","Asia/Novosibirsk"
|
||||||
|
"N. Central Asia Standard Time","RU","Asia/Novosibirsk Asia/Omsk"
|
||||||
|
"Namibia Standard Time","001","Africa/Windhoek"
|
||||||
|
"Namibia Standard Time","NA","Africa/Windhoek"
|
||||||
|
"Nepal Standard Time","001","Asia/Katmandu"
|
||||||
|
"Nepal Standard Time","NP","Asia/Katmandu"
|
||||||
|
"New Zealand Standard Time","001","Pacific/Auckland"
|
||||||
|
"New Zealand Standard Time","AQ","Antarctica/McMurdo"
|
||||||
|
"New Zealand Standard Time","NZ","Pacific/Auckland"
|
||||||
|
"Newfoundland Standard Time","001","America/St_Johns"
|
||||||
|
"Newfoundland Standard Time","CA","America/St_Johns"
|
||||||
|
"North Asia East Standard Time","001","Asia/Irkutsk"
|
||||||
|
"North Asia East Standard Time","RU","Asia/Irkutsk Asia/Chita"
|
||||||
|
"North Asia Standard Time","001","Asia/Krasnoyarsk"
|
||||||
|
"North Asia Standard Time","RU","Asia/Krasnoyarsk Asia/Novokuznetsk"
|
||||||
|
"Pacific SA Standard Time","001","America/Santiago"
|
||||||
|
"Pacific SA Standard Time","AQ","Antarctica/Palmer"
|
||||||
|
"Pacific SA Standard Time","CL","America/Santiago"
|
||||||
|
"Pacific Standard Time","001","America/Los_Angeles"
|
||||||
|
"Pacific Standard Time","CA","America/Vancouver America/Dawson America/Whitehorse"
|
||||||
|
"Pacific Standard Time","MX","America/Tijuana"
|
||||||
|
"Pacific Standard Time","US","America/Los_Angeles"
|
||||||
|
"Pacific Standard Time","ZZ","PST8PDT"
|
||||||
|
"Pacific Standard Time (Mexico)","001","America/Santa_Isabel"
|
||||||
|
"Pacific Standard Time (Mexico)","MX","America/Santa_Isabel"
|
||||||
|
"Pakistan Standard Time","001","Asia/Karachi"
|
||||||
|
"Pakistan Standard Time","PK","Asia/Karachi"
|
||||||
|
"Paraguay Standard Time","001","America/Asuncion"
|
||||||
|
"Paraguay Standard Time","PY","America/Asuncion"
|
||||||
|
"Romance Standard Time","001","Europe/Paris"
|
||||||
|
"Romance Standard Time","BE","Europe/Brussels"
|
||||||
|
"Romance Standard Time","DK","Europe/Copenhagen"
|
||||||
|
"Romance Standard Time","ES","Europe/Madrid Africa/Ceuta"
|
||||||
|
"Romance Standard Time","FR","Europe/Paris"
|
||||||
|
"Russia Time Zone 10","001","Asia/Srednekolymsk"
|
||||||
|
"Russia Time Zone 10","RU","Asia/Srednekolymsk"
|
||||||
|
"Russia Time Zone 11","001","Asia/Kamchatka"
|
||||||
|
"Russia Time Zone 11","RU","Asia/Kamchatka Asia/Anadyr"
|
||||||
|
"Russia Time Zone 3","001","Europe/Samara"
|
||||||
|
"Russia Time Zone 3","RU","Europe/Samara"
|
||||||
|
"Russian Standard Time","001","Europe/Moscow"
|
||||||
|
"Russian Standard Time","RU","Europe/Moscow Europe/Simferopol Europe/Volgograd"
|
||||||
|
"SA Eastern Standard Time","001","America/Cayenne"
|
||||||
|
"SA Eastern Standard Time","AQ","Antarctica/Rothera"
|
||||||
|
"SA Eastern Standard Time","BR","America/Fortaleza America/Araguaina America/Belem America/Maceio America/Recife America/Santarem"
|
||||||
|
"SA Eastern Standard Time","FK","Atlantic/Stanley"
|
||||||
|
"SA Eastern Standard Time","GF","America/Cayenne"
|
||||||
|
"SA Eastern Standard Time","SR","America/Paramaribo"
|
||||||
|
"SA Eastern Standard Time","ZZ","Etc/GMT+3"
|
||||||
|
"SA Pacific Standard Time","001","America/Bogota"
|
||||||
|
"SA Pacific Standard Time","BR","America/Rio_Branco America/Eirunepe"
|
||||||
|
"SA Pacific Standard Time","CA","America/Coral_Harbour"
|
||||||
|
"SA Pacific Standard Time","CO","America/Bogota"
|
||||||
|
"SA Pacific Standard Time","EC","America/Guayaquil"
|
||||||
|
"SA Pacific Standard Time","JM","America/Jamaica"
|
||||||
|
"SA Pacific Standard Time","KY","America/Cayman"
|
||||||
|
"SA Pacific Standard Time","PA","America/Panama"
|
||||||
|
"SA Pacific Standard Time","PE","America/Lima"
|
||||||
|
"SA Pacific Standard Time","ZZ","Etc/GMT+5"
|
||||||
|
"SA Western Standard Time","001","America/La_Paz"
|
||||||
|
"SA Western Standard Time","AG","America/Antigua"
|
||||||
|
"SA Western Standard Time","AI","America/Anguilla"
|
||||||
|
"SA Western Standard Time","AW","America/Aruba"
|
||||||
|
"SA Western Standard Time","BB","America/Barbados"
|
||||||
|
"SA Western Standard Time","BL","America/St_Barthelemy"
|
||||||
|
"SA Western Standard Time","BO","America/La_Paz"
|
||||||
|
"SA Western Standard Time","BQ","America/Kralendijk"
|
||||||
|
"SA Western Standard Time","BR","America/Manaus America/Boa_Vista America/Porto_Velho"
|
||||||
|
"SA Western Standard Time","CA","America/Blanc-Sablon"
|
||||||
|
"SA Western Standard Time","CW","America/Curacao"
|
||||||
|
"SA Western Standard Time","DM","America/Dominica"
|
||||||
|
"SA Western Standard Time","DO","America/Santo_Domingo"
|
||||||
|
"SA Western Standard Time","GD","America/Grenada"
|
||||||
|
"SA Western Standard Time","GP","America/Guadeloupe"
|
||||||
|
"SA Western Standard Time","GY","America/Guyana"
|
||||||
|
"SA Western Standard Time","KN","America/St_Kitts"
|
||||||
|
"SA Western Standard Time","LC","America/St_Lucia"
|
||||||
|
"SA Western Standard Time","MF","America/Marigot"
|
||||||
|
"SA Western Standard Time","MQ","America/Martinique"
|
||||||
|
"SA Western Standard Time","MS","America/Montserrat"
|
||||||
|
"SA Western Standard Time","PR","America/Puerto_Rico"
|
||||||
|
"SA Western Standard Time","SX","America/Lower_Princes"
|
||||||
|
"SA Western Standard Time","TC","America/Grand_Turk"
|
||||||
|
"SA Western Standard Time","TT","America/Port_of_Spain"
|
||||||
|
"SA Western Standard Time","VC","America/St_Vincent"
|
||||||
|
"SA Western Standard Time","VG","America/Tortola"
|
||||||
|
"SA Western Standard Time","VI","America/St_Thomas"
|
||||||
|
"SA Western Standard Time","ZZ","Etc/GMT+4"
|
||||||
|
"SE Asia Standard Time","001","Asia/Bangkok"
|
||||||
|
"SE Asia Standard Time","AQ","Antarctica/Davis"
|
||||||
|
"SE Asia Standard Time","CX","Indian/Christmas"
|
||||||
|
"SE Asia Standard Time","ID","Asia/Jakarta Asia/Pontianak"
|
||||||
|
"SE Asia Standard Time","KH","Asia/Phnom_Penh"
|
||||||
|
"SE Asia Standard Time","LA","Asia/Vientiane"
|
||||||
|
"SE Asia Standard Time","MN","Asia/Hovd"
|
||||||
|
"SE Asia Standard Time","TH","Asia/Bangkok"
|
||||||
|
"SE Asia Standard Time","VN","Asia/Saigon"
|
||||||
|
"SE Asia Standard Time","ZZ","Etc/GMT-7"
|
||||||
|
"Samoa Standard Time","001","Pacific/Apia"
|
||||||
|
"Samoa Standard Time","WS","Pacific/Apia"
|
||||||
|
"Singapore Standard Time","001","Asia/Singapore"
|
||||||
|
"Singapore Standard Time","BN","Asia/Brunei"
|
||||||
|
"Singapore Standard Time","ID","Asia/Makassar"
|
||||||
|
"Singapore Standard Time","MY","Asia/Kuala_Lumpur Asia/Kuching"
|
||||||
|
"Singapore Standard Time","PH","Asia/Manila"
|
||||||
|
"Singapore Standard Time","SG","Asia/Singapore"
|
||||||
|
"Singapore Standard Time","ZZ","Etc/GMT-8"
|
||||||
|
"South Africa Standard Time","001","Africa/Johannesburg"
|
||||||
|
"South Africa Standard Time","BI","Africa/Bujumbura"
|
||||||
|
"South Africa Standard Time","BW","Africa/Gaborone"
|
||||||
|
"South Africa Standard Time","CD","Africa/Lubumbashi"
|
||||||
|
"South Africa Standard Time","LS","Africa/Maseru"
|
||||||
|
"South Africa Standard Time","MW","Africa/Blantyre"
|
||||||
|
"South Africa Standard Time","MZ","Africa/Maputo"
|
||||||
|
"South Africa Standard Time","RW","Africa/Kigali"
|
||||||
|
"South Africa Standard Time","SZ","Africa/Mbabane"
|
||||||
|
"South Africa Standard Time","ZA","Africa/Johannesburg"
|
||||||
|
"South Africa Standard Time","ZM","Africa/Lusaka"
|
||||||
|
"South Africa Standard Time","ZW","Africa/Harare"
|
||||||
|
"South Africa Standard Time","ZZ","Etc/GMT-2"
|
||||||
|
"Sri Lanka Standard Time","001","Asia/Colombo"
|
||||||
|
"Sri Lanka Standard Time","LK","Asia/Colombo"
|
||||||
|
"Syria Standard Time","001","Asia/Damascus"
|
||||||
|
"Syria Standard Time","SY","Asia/Damascus"
|
||||||
|
"Taipei Standard Time","001","Asia/Taipei"
|
||||||
|
"Taipei Standard Time","TW","Asia/Taipei"
|
||||||
|
"Tasmania Standard Time","001","Australia/Hobart"
|
||||||
|
"Tasmania Standard Time","AU","Australia/Hobart Australia/Currie"
|
||||||
|
"Tokyo Standard Time","001","Asia/Tokyo"
|
||||||
|
"Tokyo Standard Time","ID","Asia/Jayapura"
|
||||||
|
"Tokyo Standard Time","JP","Asia/Tokyo"
|
||||||
|
"Tokyo Standard Time","PW","Pacific/Palau"
|
||||||
|
"Tokyo Standard Time","TL","Asia/Dili"
|
||||||
|
"Tokyo Standard Time","ZZ","Etc/GMT-9"
|
||||||
|
"Tonga Standard Time","001","Pacific/Tongatapu"
|
||||||
|
"Tonga Standard Time","KI","Pacific/Enderbury"
|
||||||
|
"Tonga Standard Time","TK","Pacific/Fakaofo"
|
||||||
|
"Tonga Standard Time","TO","Pacific/Tongatapu"
|
||||||
|
"Tonga Standard Time","ZZ","Etc/GMT-13"
|
||||||
|
"Turkey Standard Time","001","Europe/Istanbul"
|
||||||
|
"Turkey Standard Time","TR","Europe/Istanbul"
|
||||||
|
"US Eastern Standard Time","001","America/Indianapolis"
|
||||||
|
"US Eastern Standard Time","US","America/Indianapolis America/Indiana/Marengo America/Indiana/Vevay"
|
||||||
|
"US Mountain Standard Time","001","America/Phoenix"
|
||||||
|
"US Mountain Standard Time","CA","America/Dawson_Creek America/Creston"
|
||||||
|
"US Mountain Standard Time","MX","America/Hermosillo"
|
||||||
|
"US Mountain Standard Time","US","America/Phoenix"
|
||||||
|
"US Mountain Standard Time","ZZ","Etc/GMT+7"
|
||||||
|
"UTC","001","Etc/GMT"
|
||||||
|
"UTC","GL","America/Danmarkshavn"
|
||||||
|
"UTC","ZZ","Etc/GMT"
|
||||||
|
"UTC+12","001","Etc/GMT-12"
|
||||||
|
"UTC+12","KI","Pacific/Tarawa"
|
||||||
|
"UTC+12","MH","Pacific/Majuro Pacific/Kwajalein"
|
||||||
|
"UTC+12","NR","Pacific/Nauru"
|
||||||
|
"UTC+12","TV","Pacific/Funafuti"
|
||||||
|
"UTC+12","UM","Pacific/Wake"
|
||||||
|
"UTC+12","WF","Pacific/Wallis"
|
||||||
|
"UTC+12","ZZ","Etc/GMT-12"
|
||||||
|
"UTC-02","001","Etc/GMT+2"
|
||||||
|
"UTC-02","BR","America/Noronha"
|
||||||
|
"UTC-02","GS","Atlantic/South_Georgia"
|
||||||
|
"UTC-02","ZZ","Etc/GMT+2"
|
||||||
|
"UTC-11","001","Etc/GMT+11"
|
||||||
|
"UTC-11","AS","Pacific/Pago_Pago"
|
||||||
|
"UTC-11","NU","Pacific/Niue"
|
||||||
|
"UTC-11","UM","Pacific/Midway"
|
||||||
|
"UTC-11","ZZ","Etc/GMT+11"
|
||||||
|
"Ulaanbaatar Standard Time","001","Asia/Ulaanbaatar"
|
||||||
|
"Ulaanbaatar Standard Time","MN","Asia/Ulaanbaatar Asia/Choibalsan"
|
||||||
|
"Venezuela Standard Time","001","America/Caracas"
|
||||||
|
"Venezuela Standard Time","VE","America/Caracas"
|
||||||
|
"Vladivostok Standard Time","001","Asia/Vladivostok"
|
||||||
|
"Vladivostok Standard Time","RU","Asia/Vladivostok Asia/Sakhalin Asia/Ust-Nera"
|
||||||
|
"W. Australia Standard Time","001","Australia/Perth"
|
||||||
|
"W. Australia Standard Time","AQ","Antarctica/Casey"
|
||||||
|
"W. Australia Standard Time","AU","Australia/Perth"
|
||||||
|
"W. Central Africa Standard Time","001","Africa/Lagos"
|
||||||
|
"W. Central Africa Standard Time","AO","Africa/Luanda"
|
||||||
|
"W. Central Africa Standard Time","BJ","Africa/Porto-Novo"
|
||||||
|
"W. Central Africa Standard Time","CD","Africa/Kinshasa"
|
||||||
|
"W. Central Africa Standard Time","CF","Africa/Bangui"
|
||||||
|
"W. Central Africa Standard Time","CG","Africa/Brazzaville"
|
||||||
|
"W. Central Africa Standard Time","CM","Africa/Douala"
|
||||||
|
"W. Central Africa Standard Time","DZ","Africa/Algiers"
|
||||||
|
"W. Central Africa Standard Time","GA","Africa/Libreville"
|
||||||
|
"W. Central Africa Standard Time","GQ","Africa/Malabo"
|
||||||
|
"W. Central Africa Standard Time","NE","Africa/Niamey"
|
||||||
|
"W. Central Africa Standard Time","NG","Africa/Lagos"
|
||||||
|
"W. Central Africa Standard Time","TD","Africa/Ndjamena"
|
||||||
|
"W. Central Africa Standard Time","TN","Africa/Tunis"
|
||||||
|
"W. Central Africa Standard Time","ZZ","Etc/GMT-1"
|
||||||
|
"W. Europe Standard Time","001","Europe/Berlin"
|
||||||
|
"W. Europe Standard Time","AD","Europe/Andorra"
|
||||||
|
"W. Europe Standard Time","AT","Europe/Vienna"
|
||||||
|
"W. Europe Standard Time","CH","Europe/Zurich"
|
||||||
|
"W. Europe Standard Time","DE","Europe/Berlin Europe/Busingen"
|
||||||
|
"W. Europe Standard Time","GI","Europe/Gibraltar"
|
||||||
|
"W. Europe Standard Time","IT","Europe/Rome"
|
||||||
|
"W. Europe Standard Time","LI","Europe/Vaduz"
|
||||||
|
"W. Europe Standard Time","LU","Europe/Luxembourg"
|
||||||
|
"W. Europe Standard Time","MC","Europe/Monaco"
|
||||||
|
"W. Europe Standard Time","MT","Europe/Malta"
|
||||||
|
"W. Europe Standard Time","NL","Europe/Amsterdam"
|
||||||
|
"W. Europe Standard Time","NO","Europe/Oslo"
|
||||||
|
"W. Europe Standard Time","SE","Europe/Stockholm"
|
||||||
|
"W. Europe Standard Time","SJ","Arctic/Longyearbyen"
|
||||||
|
"W. Europe Standard Time","SM","Europe/San_Marino"
|
||||||
|
"W. Europe Standard Time","VA","Europe/Vatican"
|
||||||
|
"West Asia Standard Time","001","Asia/Tashkent"
|
||||||
|
"West Asia Standard Time","AQ","Antarctica/Mawson"
|
||||||
|
"West Asia Standard Time","KZ","Asia/Oral Asia/Aqtau Asia/Aqtobe"
|
||||||
|
"West Asia Standard Time","MV","Indian/Maldives"
|
||||||
|
"West Asia Standard Time","TF","Indian/Kerguelen"
|
||||||
|
"West Asia Standard Time","TJ","Asia/Dushanbe"
|
||||||
|
"West Asia Standard Time","TM","Asia/Ashgabat"
|
||||||
|
"West Asia Standard Time","UZ","Asia/Tashkent Asia/Samarkand"
|
||||||
|
"West Asia Standard Time","ZZ","Etc/GMT-5"
|
||||||
|
"West Pacific Standard Time","001","Pacific/Port_Moresby"
|
||||||
|
"West Pacific Standard Time","AQ","Antarctica/DumontDUrville"
|
||||||
|
"West Pacific Standard Time","FM","Pacific/Truk"
|
||||||
|
"West Pacific Standard Time","GU","Pacific/Guam"
|
||||||
|
"West Pacific Standard Time","MP","Pacific/Saipan"
|
||||||
|
"West Pacific Standard Time","PG","Pacific/Port_Moresby"
|
||||||
|
"West Pacific Standard Time","ZZ","Etc/GMT-10"
|
||||||
|
"Yakutsk Standard Time","001","Asia/Yakutsk"
|
||||||
|
"Yakutsk Standard Time","RU","Asia/Yakutsk Asia/Khandyga"
|
|
9
date.h
9
date.h
@@ -22,7 +22,14 @@ namespace date
|
|||||||
// Configuration |
|
// Configuration |
|
||||||
//---------------+
|
//---------------+
|
||||||
|
|
||||||
#if __cplusplus >= 201402
|
// MSVC's constexpr support is still a WIP, even in VS2015.
|
||||||
|
// Fall back to a lesser mode to support it.
|
||||||
|
// TODO: Remove this or retest later once MSVC's constexpr improves.
|
||||||
|
#if defined(_MSC_VER) && ! defined(__clang__) && ! defined( __GNUG__)
|
||||||
|
# define CONSTDATA const
|
||||||
|
# define CONSTCD11
|
||||||
|
# define CONSTCD14
|
||||||
|
#elif __cplusplus >= 201402
|
||||||
# define CONSTDATA constexpr
|
# define CONSTDATA constexpr
|
||||||
# define CONSTCD11 constexpr
|
# define CONSTCD11 constexpr
|
||||||
# define CONSTCD14 constexpr
|
# define CONSTCD14 constexpr
|
||||||
|
436
tz.cpp
436
tz.cpp
@@ -10,21 +10,92 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TIMEZONE_MAPPING
|
||||||
|
// Timezone mapping is mapping native timezone names to "Standard" ones.
|
||||||
|
// Mapping reades a CSV file for the data and currently uses
|
||||||
|
// std::quoted to do that which is a C++14 feature found in iomanip.
|
||||||
|
// VS2015 supports std::quoted but MSVC has a mixed rather
|
||||||
|
// than strict standard support so there is no -std=c++14 flag for MSVC.
|
||||||
|
// MingW is a Windows based platform so requires mapping and thefore C++14.
|
||||||
|
// Linux/Mac currently do not require mapping so C++14 isn't needed for this
|
||||||
|
// so C++11 should work.
|
||||||
|
#include <iomanip>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// unistd.h is used on some platforms as part of the the means to get
|
||||||
|
// the current time zone. However unistd.h only somtimes exists on Win32.
|
||||||
|
// gcc/mingw support unistd.h on Win32 but MSVC does not.
|
||||||
|
// However on Win32 we don't need unistd.h anyway to get the current timezone
|
||||||
|
// as Windows.h provides a means to do it
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Until filesystem arrives.
|
||||||
|
static const char folder_delimiter =
|
||||||
|
#ifdef _WIN32
|
||||||
|
'\\';
|
||||||
|
#else
|
||||||
|
'/';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Win32 support requires calling OS functions.
|
||||||
|
// This routine maps OS error codes to readable text strngs.
|
||||||
|
static std::string get_win32_message(DWORD error_code)
|
||||||
|
{
|
||||||
|
struct free_message {
|
||||||
|
void operator()(char buf[]) {
|
||||||
|
if (buf != nullptr)
|
||||||
|
{
|
||||||
|
auto result = HeapFree(GetProcessHeap(), 0, buf);
|
||||||
|
assert(result != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
char* msg = nullptr;
|
||||||
|
auto result = FormatMessageA(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
|
||||||
|
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
reinterpret_cast<char*>(&msg), 0, NULL );
|
||||||
|
std::unique_ptr<char[], free_message> message_buffer(msg);
|
||||||
|
if (result == 0) // If there is no error message, still give the code.
|
||||||
|
{
|
||||||
|
std::string err = "Error getting message for error number ";
|
||||||
|
err += std::to_string(error_code);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
assert(message_buffer.get() != nullptr);
|
||||||
|
return std::string(message_buffer.get());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace date
|
namespace date
|
||||||
{
|
{
|
||||||
|
|
||||||
// +---------------------+
|
// +---------------------+
|
||||||
// | Begin Configuration |
|
// | Begin Configuration |
|
||||||
// +---------------------+
|
// +---------------------+
|
||||||
|
|
||||||
static std::string install{"/Users/howardhinnant/Downloads/tzdata2015e"};
|
#if _WIN32 // TODO: sensible default for all platforms.
|
||||||
|
static std::string install{ "c:\\tzdata" };
|
||||||
|
#else
|
||||||
|
static std::string install{ "/Users/howardhinnant/Downloads/tzdata2015e" };
|
||||||
|
#endif
|
||||||
|
|
||||||
static const std::vector<std::string> files =
|
static const std::vector<std::string> files =
|
||||||
{
|
{
|
||||||
@@ -44,11 +115,294 @@ CONSTDATA auto boring_day = date::aug/18;
|
|||||||
// | End Configuration |
|
// | End Configuration |
|
||||||
// +-------------------+
|
// +-------------------+
|
||||||
|
|
||||||
|
#if _MSC_VER && ! defined(__clang__) && ! defined( __GNUG__)
|
||||||
|
// We can't use static_assert here for MSVC (yet) because
|
||||||
|
// the expression isn't constexpr in MSVC yet.
|
||||||
|
// FIXME! Remove this when MSVC's constexpr support improves.
|
||||||
|
#else
|
||||||
static_assert(min_year <= max_year, "Configuration error");
|
static_assert(min_year <= max_year, "Configuration error");
|
||||||
|
#endif
|
||||||
#if __cplusplus >= 201402
|
#if __cplusplus >= 201402
|
||||||
static_assert(boring_day.ok(), "Configuration error");
|
static_assert(boring_day.ok(), "Configuration error");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if TIMEZONE_MAPPING
|
||||||
|
|
||||||
|
namespace // Put types in an aonymous name space.
|
||||||
|
{
|
||||||
|
// A simple type to manage RAII for key handles and to
|
||||||
|
// implement the trivial registry interface we need.
|
||||||
|
// Not itended to be general purpose.
|
||||||
|
class reg_key
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// Note there is no value documented to be an invalid handle value.
|
||||||
|
// Not NULL nor INVALID_HANDLE_VALUE. We must rely on is_open.
|
||||||
|
HKEY m_key = NULL;
|
||||||
|
bool m_is_open = false;
|
||||||
|
public:
|
||||||
|
HKEY handle()
|
||||||
|
{
|
||||||
|
return m_key;
|
||||||
|
}
|
||||||
|
bool is_open() const
|
||||||
|
{
|
||||||
|
return m_is_open;
|
||||||
|
}
|
||||||
|
LONG open(const wchar_t* key_name)
|
||||||
|
{
|
||||||
|
LONG result;
|
||||||
|
result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &m_key);
|
||||||
|
if (result == ERROR_SUCCESS)
|
||||||
|
m_is_open = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
LONG close()
|
||||||
|
{
|
||||||
|
if (m_is_open)
|
||||||
|
{
|
||||||
|
auto result = RegCloseKey(m_key);
|
||||||
|
assert(result == ERROR_SUCCESS);
|
||||||
|
if (result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
m_is_open = false;
|
||||||
|
m_key = NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: this function has a hard code value size limit.
|
||||||
|
// It is not a general purpose function.
|
||||||
|
// It should be sufficient for our use cases.
|
||||||
|
// The function could be made workable for any size string
|
||||||
|
// but we don't need the complexity of implementing that
|
||||||
|
// for our meagre purposes right now.
|
||||||
|
bool get_string(const wchar_t* key_name, std::string& value)
|
||||||
|
{
|
||||||
|
value.clear();
|
||||||
|
wchar_t value_buffer[256];
|
||||||
|
// in/out parameter. Documentation say that size is a count of bytes not chars.
|
||||||
|
DWORD size = sizeof(value_buffer);
|
||||||
|
DWORD tzi_type = REG_SZ;
|
||||||
|
if (RegQueryValueExW(handle(), key_name, nullptr, &tzi_type,
|
||||||
|
reinterpret_cast<LPBYTE>(value_buffer), &size) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
// Function does not guarantee to null terminate.
|
||||||
|
value_buffer[size] = L'\0';
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
value = converter.to_bytes(value_buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_binary(const wchar_t* key_name, void* value, int value_size)
|
||||||
|
{
|
||||||
|
DWORD size = value_size;
|
||||||
|
DWORD type = REG_BINARY;
|
||||||
|
if (RegQueryValueExW(handle(), key_name, nullptr, &type,
|
||||||
|
reinterpret_cast<LPBYTE>(value), &size) == ERROR_SUCCESS
|
||||||
|
&& (int) size == value_size)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
~reg_key()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
template < typename T, size_t N >
|
||||||
|
static inline size_t countof(T(&arr)[N])
|
||||||
|
{
|
||||||
|
return std::extent< T[N] >::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function return an exhaustive list of time zone information
|
||||||
|
// from the Windows registry.
|
||||||
|
// The routine tries to to obtain as much information as possible despite errors.
|
||||||
|
// If there is an error with any key, it is silently ignored to move on to the next.
|
||||||
|
// We don't have a logger to log such errors and it might disruptive to log anyway.
|
||||||
|
// We don't want the whole database of information disrupted just because
|
||||||
|
// one record of in it can't be read.
|
||||||
|
// The expectation is that the errors will eventually manifest to the
|
||||||
|
// caller as a missing time zone which they will need to investigate.
|
||||||
|
|
||||||
|
static void get_windows_timezone_info(std::vector<timezone_info>& tz_list)
|
||||||
|
{
|
||||||
|
tz_list.clear();
|
||||||
|
LONG result;
|
||||||
|
|
||||||
|
// Open the parent time zone key that has the list of timzeones in.
|
||||||
|
reg_key zones_key;
|
||||||
|
static const wchar_t zones_key_name[] = { L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones" };
|
||||||
|
result = zones_key.open(zones_key_name);
|
||||||
|
// TODO! Review if this should happen here or be signalled later.
|
||||||
|
// We don't want process to fail on startup because of this or something.
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
throw std::runtime_error("Time Zone registry key could not be opened: " + get_win32_message(result));
|
||||||
|
|
||||||
|
DWORD size;
|
||||||
|
wchar_t zone_key_name[256];
|
||||||
|
std::wstring value;
|
||||||
|
|
||||||
|
// Iterate through the list of keys of the parent time zones key to get
|
||||||
|
// each key that identifies each individual timezone.
|
||||||
|
std::wstring full_zone_key_name;
|
||||||
|
for (DWORD zone_index = 0; ; ++zone_index)
|
||||||
|
{
|
||||||
|
timezone_info tz;
|
||||||
|
|
||||||
|
size = (DWORD) sizeof(zone_key_name);
|
||||||
|
auto status = RegEnumKeyExW(zones_key.handle(), zone_index, zone_key_name, &size,
|
||||||
|
nullptr, nullptr, nullptr, nullptr);
|
||||||
|
if (status != ERROR_SUCCESS && status != ERROR_NO_MORE_ITEMS)
|
||||||
|
throw std::runtime_error("Can't enumerate time zone registry key" + get_win32_message(status));
|
||||||
|
if (status == ERROR_NO_MORE_ITEMS)
|
||||||
|
break;
|
||||||
|
zone_key_name[size] = L'\0';
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
tz.timezone_id = converter.to_bytes(zone_key_name);
|
||||||
|
|
||||||
|
full_zone_key_name = zones_key_name;
|
||||||
|
full_zone_key_name += L'\\';
|
||||||
|
full_zone_key_name += zone_key_name;
|
||||||
|
|
||||||
|
// If any field fails to be found consider the whole time zone
|
||||||
|
// entry corrupt and move onto the next. See comments
|
||||||
|
// at top of function.
|
||||||
|
|
||||||
|
reg_key zone_key;
|
||||||
|
if (zone_key.open(full_zone_key_name.c_str()) != ERROR_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!zone_key.get_string(L"Std", tz.standard_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TBD if these fields are not required yet.
|
||||||
|
// The might be useful for test cases though.
|
||||||
|
if (!zone_key.get_string("Display", tz.display_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!zone_key.get_binary("TZI", &tz.tzi, sizeof(TZI)))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
auto result = zone_key.close();
|
||||||
|
|
||||||
|
tz_list.push_back(std::move(tz));
|
||||||
|
}
|
||||||
|
result = zones_key.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// standard_name is the StandardName field from the Windows
|
||||||
|
// TIME_ZONE_INFORMATION structure.
|
||||||
|
// See the Windows API function GetTimeZoneInformation.
|
||||||
|
// The standard_name is also the value from STD field of
|
||||||
|
// under the windows registry key Time Zones.
|
||||||
|
// To be clear standard_name does NOT represent a windows timezone id
|
||||||
|
// or an IANA tzid
|
||||||
|
static const timezone_info* find_native_timezone_by_standard_name(
|
||||||
|
const std::string& standard_name)
|
||||||
|
{
|
||||||
|
// TODO! we can improve on linear search.
|
||||||
|
const auto& native_zones = get_tzdb().native_zones;
|
||||||
|
for (const auto& tz : native_zones)
|
||||||
|
{
|
||||||
|
if (tz.standard_name == standard_name)
|
||||||
|
return &tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read CSV file of "other","territory","type".
|
||||||
|
// See timezone_mapping structure for more info.
|
||||||
|
// This function should be kept in sync the code/ that writes this file.
|
||||||
|
static std::vector<timezone_mapping>
|
||||||
|
load_timezone_mappings_from_csv_file(const std::string& input_path)
|
||||||
|
{
|
||||||
|
size_t line = 1;
|
||||||
|
std::vector<timezone_mapping> mappings;
|
||||||
|
std::ifstream is(input_path, std::ios_base::in | std::ios_base::binary);
|
||||||
|
if (!is.is_open())
|
||||||
|
{
|
||||||
|
// We don't emit file exceptions because that's an implementation detail.
|
||||||
|
std::string msg = "Error opening time zone mapping file: ";
|
||||||
|
msg += input_path;
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
auto error = [&](const char* info)
|
||||||
|
{
|
||||||
|
std::string msg = "Error reading zone mapping file at line ";
|
||||||
|
msg += std::to_string(line);
|
||||||
|
msg += ": ";
|
||||||
|
msg += info;
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto read_field_delim = [&]()
|
||||||
|
{
|
||||||
|
char field_delim;
|
||||||
|
is.read(&field_delim, 1);
|
||||||
|
if (is.gcount() != 1 || field_delim != ',')
|
||||||
|
error("delimiter ',' expected");
|
||||||
|
};
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
timezone_mapping zm{};
|
||||||
|
is >> std::quoted(zm.other);
|
||||||
|
if (is.eof())
|
||||||
|
break;
|
||||||
|
|
||||||
|
read_field_delim();
|
||||||
|
is >> std::quoted(zm.territory);
|
||||||
|
read_field_delim();
|
||||||
|
is >> std::quoted(zm.type);
|
||||||
|
|
||||||
|
char record_delim;
|
||||||
|
is.read(&record_delim, 1);
|
||||||
|
if (is.gcount() != 1 || record_delim != '\n')
|
||||||
|
error("record delimiter LF expected");
|
||||||
|
|
||||||
|
if (is.fail() || is.eof())
|
||||||
|
error("unexpected end of file, file read error or formatting error.");
|
||||||
|
++line;
|
||||||
|
mappings.push_back(std::move(zm));
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
native_to_standard_timezone_name(const std::string& native_tz_name, std::string& standard_tz_name)
|
||||||
|
{
|
||||||
|
// TOOD! Need be a case insensitive compare?
|
||||||
|
if (native_tz_name == "UTC")
|
||||||
|
{
|
||||||
|
standard_tz_name = "Etc/UTC";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
standard_tz_name.clear();
|
||||||
|
// TODO! we can improve on linear search.
|
||||||
|
const auto& mappings = date::get_tzdb().mappings;
|
||||||
|
for (const auto& tzm : mappings)
|
||||||
|
{
|
||||||
|
if (tzm.other == native_tz_name)
|
||||||
|
{
|
||||||
|
standard_tz_name = tzm.type;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Parsing helpers
|
// Parsing helpers
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -67,7 +421,7 @@ static
|
|||||||
unsigned
|
unsigned
|
||||||
parse_dow(std::istream& in)
|
parse_dow(std::istream& in)
|
||||||
{
|
{
|
||||||
CONSTDATA const char* dow_names[] =
|
const char*const dow_names[] =
|
||||||
{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||||
auto s = parse3(in);
|
auto s = parse3(in);
|
||||||
auto dow = std::find(std::begin(dow_names), std::end(dow_names), s) - dow_names;
|
auto dow = std::find(std::begin(dow_names), std::end(dow_names), s) - dow_names;
|
||||||
@@ -80,7 +434,7 @@ static
|
|||||||
unsigned
|
unsigned
|
||||||
parse_month(std::istream& in)
|
parse_month(std::istream& in)
|
||||||
{
|
{
|
||||||
CONSTDATA const char* month_names[] =
|
const char*const month_names[] =
|
||||||
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||||
auto s = parse3(in);
|
auto s = parse3(in);
|
||||||
@@ -1032,6 +1386,9 @@ find_rule_for_zone(const std::pair<const Rule*, const Rule*>& eqr,
|
|||||||
const date::year& y, const std::chrono::seconds& offset,
|
const date::year& y, const std::chrono::seconds& offset,
|
||||||
const MonthDayTime& mdt)
|
const MonthDayTime& mdt)
|
||||||
{
|
{
|
||||||
|
assert(eqr.first != nullptr);
|
||||||
|
assert(eqr.second != nullptr);
|
||||||
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace date;
|
using namespace date;
|
||||||
auto r = eqr.first;
|
auto r = eqr.first;
|
||||||
@@ -1437,7 +1794,7 @@ TZ_DB
|
|||||||
init_tzdb()
|
init_tzdb()
|
||||||
{
|
{
|
||||||
using namespace date;
|
using namespace date;
|
||||||
const std::string path = install + "/";
|
const std::string path = install + folder_delimiter;
|
||||||
std::string line;
|
std::string line;
|
||||||
bool continue_zone = false;
|
bool continue_zone = false;
|
||||||
TZ_DB db;
|
TZ_DB db;
|
||||||
@@ -1493,6 +1850,13 @@ init_tzdb()
|
|||||||
db.links.shrink_to_fit();
|
db.links.shrink_to_fit();
|
||||||
std::sort(db.leaps.begin(), db.leaps.end());
|
std::sort(db.leaps.begin(), db.leaps.end());
|
||||||
db.leaps.shrink_to_fit();
|
db.leaps.shrink_to_fit();
|
||||||
|
|
||||||
|
#if TIMEZONE_MAPPING
|
||||||
|
std::string mapping_file = path + "TimeZoneMappings.csv";
|
||||||
|
db.mappings = load_timezone_mappings_from_csv_file(mapping_file);
|
||||||
|
get_windows_timezone_info(db.native_zones);
|
||||||
|
#endif
|
||||||
|
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1555,6 +1919,25 @@ locate_zone(const std::string& tz_name)
|
|||||||
return &*zi;
|
return &*zi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TZ_TEST
|
||||||
|
#ifdef _WIN32
|
||||||
|
const Zone*
|
||||||
|
locate_native_zone(const std::string& native_tz_name)
|
||||||
|
{
|
||||||
|
std::string standard_tz_name;
|
||||||
|
if (!native_to_standard_timezone_name(native_tz_name, standard_tz_name))
|
||||||
|
{
|
||||||
|
std::string msg;
|
||||||
|
msg = "locate_native_zone() failed: A mapping from the Windows Time Zone id \"";
|
||||||
|
msg += native_tz_name;
|
||||||
|
msg += "\" was not found in the time zone mapping database.";
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
return locate_zone(standard_tz_name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<<(std::ostream& os, const TZ_DB& db)
|
operator<<(std::ostream& os, const TZ_DB& db)
|
||||||
{
|
{
|
||||||
@@ -1625,6 +2008,48 @@ operator<<(std::ostream& os, const Info& r)
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
const Zone*
|
||||||
|
current_timezone()
|
||||||
|
{
|
||||||
|
#if TIMEZONE_MAPPING
|
||||||
|
TIME_ZONE_INFORMATION tzi{};
|
||||||
|
DWORD tz_result = ::GetTimeZoneInformation(&tzi);
|
||||||
|
if (tz_result == TIME_ZONE_ID_INVALID)
|
||||||
|
{
|
||||||
|
auto error_code = ::GetLastError(); // Store this quick before it gets overwritten.
|
||||||
|
throw std::runtime_error("GetTimeZoneInformation failed: " + get_win32_message(error_code));
|
||||||
|
}
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||||
|
std::string standard_name(converter.to_bytes(tzi.StandardName));
|
||||||
|
auto tz = find_native_timezone_by_standard_name(standard_name);
|
||||||
|
if (!tz)
|
||||||
|
{
|
||||||
|
std::string msg;
|
||||||
|
msg = "current_timezone() failed: ";
|
||||||
|
msg += standard_name;
|
||||||
|
msg += " was not found in the Windows Time Zone registry";
|
||||||
|
throw std::runtime_error( msg );
|
||||||
|
}
|
||||||
|
std::string standard_tzid;
|
||||||
|
if (!native_to_standard_timezone_name(tz->timezone_id, standard_tzid))
|
||||||
|
{
|
||||||
|
std::string msg;
|
||||||
|
msg = "current_timezone() failed: A mapping from the Windows Time Zone id \"";
|
||||||
|
msg += tz->timezone_id;
|
||||||
|
msg += "\" was not found in the time zone mapping database.";
|
||||||
|
throw std::runtime_error(msg);
|
||||||
|
}
|
||||||
|
return date::locate_zone(standard_tzid);
|
||||||
|
#else
|
||||||
|
// Currently Win32 requires mapping for this function to work.
|
||||||
|
throw std::runtime_error("current_timezone not implemented.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // ! WIN32
|
||||||
|
|
||||||
const Zone*
|
const Zone*
|
||||||
current_timezone()
|
current_timezone()
|
||||||
{
|
{
|
||||||
@@ -1677,5 +2102,6 @@ current_timezone()
|
|||||||
result.erase(0, zonepath_len+pos);
|
result.erase(0, zonepath_len+pos);
|
||||||
return locate_zone(result);
|
return locate_zone(result);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace date
|
} // namespace date
|
||||||
|
94
tz.h
94
tz.h
@@ -11,6 +11,30 @@
|
|||||||
// 1. Reload database.
|
// 1. Reload database.
|
||||||
// 4. Is the utc to sys renaming complete? Was it done correctly?
|
// 4. Is the utc to sys renaming complete? Was it done correctly?
|
||||||
|
|
||||||
|
/*
|
||||||
|
The notion of "current timezone" is something the operating system is expected
|
||||||
|
to "just know". How it knows this is system specific. It's often a value
|
||||||
|
set by the user at OS intallation time and recorded by the OS somewhere.
|
||||||
|
On Linux and Mac systems. the current timezone name is obtained by looking at
|
||||||
|
the name or contents of a particular file on disk.
|
||||||
|
On Windows the current timzeone name comes from the registry.
|
||||||
|
But however the name is obtained there is no guarante
|
||||||
|
that the "native" current timezone name obtained in this way
|
||||||
|
will match any of the "Standard" names in this library's "database".
|
||||||
|
On Linux, the names usually do seem to match so mapping functions to map from
|
||||||
|
native to "Standard" are typically NOT required.
|
||||||
|
On Windows, the names are never Standard mapping is always required.
|
||||||
|
One should not equate the mapping process with Windows.
|
||||||
|
Windows is just currently the only client of them.
|
||||||
|
Technically any OS may required mapping.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef TIMEZONE_MAPPING
|
||||||
|
#define TIMEZONE_MAPPING 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "date.h"
|
#include "date.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -462,12 +486,77 @@ operator>=(const std::chrono::time_point<std::chrono::system_clock, Duration>& x
|
|||||||
return !(x < y);
|
return !(x < y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TIMEZONE_MAPPING
|
||||||
|
|
||||||
|
// TODO! Ensure all these types aren't exposed.
|
||||||
|
|
||||||
|
// The time zone mapping is modelled after this data file:
|
||||||
|
// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
|
||||||
|
// and the field names match the element names from the mapZone element
|
||||||
|
// of windowsZones.xml.
|
||||||
|
// The website displays this file here:
|
||||||
|
// http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html
|
||||||
|
// The html view is sorted before being displayed but is otherwise the same
|
||||||
|
// There is a mapping between the os centric view (in this case windows)
|
||||||
|
// the html displays uses and the generic view the xml file.
|
||||||
|
// That mapping is this:
|
||||||
|
// display column "windows" -> xml field "other".
|
||||||
|
// display column "region" -> xml field "territory".
|
||||||
|
// display column "tzid" -> xml field "type".
|
||||||
|
// This structure uses the generic terminology because it could be
|
||||||
|
// used to to support other os/native name conversions, not just windows,
|
||||||
|
// and using the same generic names helps retain the connection to the
|
||||||
|
// origin of the data that we are using.
|
||||||
|
struct timezone_mapping
|
||||||
|
{
|
||||||
|
timezone_mapping(const char* other, const char* territory, const char* type)
|
||||||
|
: other(other), territory(territory), type(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
timezone_mapping() = default;
|
||||||
|
std::string other;
|
||||||
|
std::string territory;
|
||||||
|
std::string type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// This represents the type for the tzi field in the windows registry.
|
||||||
|
// It's TBD if we need this yet.
|
||||||
|
struct TZI
|
||||||
|
{
|
||||||
|
TZI() = default;
|
||||||
|
int Bias;
|
||||||
|
int StandardBias;
|
||||||
|
int DaylightBias;
|
||||||
|
SYSTEMTIME StandardDate;
|
||||||
|
SYSTEMTIME DaylightDate;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct timezone_info
|
||||||
|
{
|
||||||
|
timezone_info() = default;
|
||||||
|
std::string timezone_id;
|
||||||
|
std::string standard_name;
|
||||||
|
#if 0 // TBD
|
||||||
|
std::string display_name;
|
||||||
|
TZI tzi;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
struct TZ_DB
|
struct TZ_DB
|
||||||
{
|
{
|
||||||
std::vector<Zone> zones;
|
std::vector<Zone> zones;
|
||||||
std::vector<Link> links;
|
std::vector<Link> links;
|
||||||
std::vector<Leap> leaps;
|
std::vector<Leap> leaps;
|
||||||
std::vector<Rule> rules;
|
std::vector<Rule> rules;
|
||||||
|
#if TIMEZONE_MAPPING
|
||||||
|
// TODO! These need some protection.
|
||||||
|
std::vector<timezone_mapping> mappings;
|
||||||
|
std::vector<timezone_info> native_zones;
|
||||||
|
#endif
|
||||||
|
|
||||||
TZ_DB() = default;
|
TZ_DB() = default;
|
||||||
TZ_DB(TZ_DB&&) = default;
|
TZ_DB(TZ_DB&&) = default;
|
||||||
@@ -481,6 +570,11 @@ const TZ_DB& reload_tzdb();
|
|||||||
const TZ_DB& reload_tzdb(const std::string& new_install);
|
const TZ_DB& reload_tzdb(const std::string& new_install);
|
||||||
|
|
||||||
const Zone* locate_zone(const std::string& tz_name);
|
const Zone* locate_zone(const std::string& tz_name);
|
||||||
|
#ifdef TZ_TEST
|
||||||
|
#ifdef _WIN32
|
||||||
|
const Zone* locate_native_zone(const std::string& native_tz_name);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
const Zone* current_timezone();
|
const Zone* current_timezone();
|
||||||
|
|
||||||
class utc_clock
|
class utc_clock
|
||||||
|
Reference in New Issue
Block a user