mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
[winpr,timezone] refactor timezone mapping
* add option to use ICU as a fallback mapping (eliminate need for WindowsZones mapping list) * extract timezone related settings from localtime_r and eliminate the need to parse the complex TimeZones table * Add new TimeZoneNameMap to map IANA to windows names (Id, Standard, Daylight and Display names) * Implement GetDynamicTimeZoneInformation
This commit is contained in:
@@ -57,6 +57,10 @@ extern "C"
|
||||
} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION,
|
||||
*LPDYNAMIC_TIME_ZONE_INFORMATION;
|
||||
|
||||
#define TIME_ZONE_ID_UNKNOWN 0
|
||||
#define TIME_ZONE_ID_STANDARD 1
|
||||
#define TIME_ZONE_ID_DAYLIGHT 2
|
||||
|
||||
WINPR_API DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation);
|
||||
WINPR_API BOOL SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation);
|
||||
WINPR_API BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, LPFILETIME lpFileTime);
|
||||
|
||||
@@ -15,4 +15,28 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
winpr_module_add(timezone.c TimeZones.c WindowsZones.c TimeZones.h WindowsZones.h)
|
||||
set(SRCS
|
||||
TimeZoneNameMap.c
|
||||
TimeZoneNameMap.h
|
||||
TimeZoneNameMapUtils.c
|
||||
)
|
||||
if (NOT WIN32)
|
||||
list(APPEND SRCS
|
||||
timezone.c
|
||||
)
|
||||
endif()
|
||||
|
||||
option(WITH_TIMEZONE_ICU "Use ICU for improved timezone mapping" OFF)
|
||||
if (WITH_TIMEZONE_ICU)
|
||||
find_package(ICU COMPONENTS i18n uc REQUIRED)
|
||||
winpr_include_directory_add(${ICU_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${ICU_LIBRARIES})
|
||||
winpr_definition_add(-DWITH_TIMEZONE_ICU)
|
||||
else()
|
||||
list(APPEND SRCS
|
||||
WindowsZones.c
|
||||
WindowsZones.h
|
||||
)
|
||||
endif()
|
||||
|
||||
winpr_module_add(${SRCS})
|
||||
|
||||
289
winpr/libwinpr/timezone/TimeZoneNameMap.c
Normal file
289
winpr/libwinpr/timezone/TimeZoneNameMap.c
Normal file
@@ -0,0 +1,289 @@
|
||||
#include "TimeZoneNameMap.h"
|
||||
|
||||
const TimeZoneNameMapEntry TimeZoneNameMap[] = {
|
||||
{ "Dateline Standard Time", "Dateline Standard Time",
|
||||
"(UTC-12:00) International Date Line West", "Dateline Daylight Time", "Etc/GMT+12" },
|
||||
{ "UTC-11", "UTC-11", "(UTC-11:00) Coordinated Universal Time-11", "UTC-11", "Etc/GMT+11" },
|
||||
{ "Aleutian Standard Time", "Aleutian Standard Time", "(UTC-10:00) Aleutian Islands",
|
||||
"Aleutian Daylight Time", "America/Adak" },
|
||||
{ "Hawaiian Standard Time", "Hawaiian Standard Time", "(UTC-10:00) Hawaii",
|
||||
"Hawaiian Daylight Time", "Pacific/Honolulu" },
|
||||
{ "Marquesas Standard Time", "Marquesas Standard Time", "(UTC-09:30) Marquesas Islands",
|
||||
"Marquesas Daylight Time", "Pacific/Marquesas" },
|
||||
{ "Alaskan Standard Time", "Alaskan Standard Time", "(UTC-09:00) Alaska",
|
||||
"Alaskan Daylight Time", "America/Anchorage" },
|
||||
{ "UTC-09", "UTC-09", "(UTC-09:00) Coordinated Universal Time-09", "UTC-09", "Etc/GMT+9" },
|
||||
{ "Pacific Standard Time (Mexico)", "Pacific Standard Time (Mexico)",
|
||||
"(UTC-08:00) Baja California", "Pacific Daylight Time (Mexico)", "America/Tijuana" },
|
||||
{ "UTC-08", "UTC-08", "(UTC-08:00) Coordinated Universal Time-08", "UTC-08", "Etc/GMT+8" },
|
||||
{ "Pacific Standard Time", "Pacific Standard Time", "(UTC-08:00) Pacific Time (US & Canada)",
|
||||
"Pacific Daylight Time", "America/Los_Angeles" },
|
||||
{ "US Mountain Standard Time", "US Mountain Standard Time", "(UTC-07:00) Arizona",
|
||||
"US Mountain Daylight Time", "America/Phoenix" },
|
||||
{ "Mountain Standard Time (Mexico)", "Mountain Standard Time (Mexico)",
|
||||
"(UTC-07:00) La Paz, Mazatlan", "Mountain Daylight Time (Mexico)", "America/Chihuahua" },
|
||||
{ "Mountain Standard Time", "Mountain Standard Time", "(UTC-07:00) Mountain Time (US & Canada)",
|
||||
"Mountain Daylight Time", "America/Denver" },
|
||||
{ "Yukon Standard Time", "Yukon Standard Time", "(UTC-07:00) Yukon", "Yukon Daylight Time",
|
||||
"America/Whitehorse" },
|
||||
{ "Central America Standard Time", "Central America Standard Time",
|
||||
"(UTC-06:00) Central America", "Central America Daylight Time", "America/Guatemala" },
|
||||
{ "Central Standard Time", "Central Standard Time", "(UTC-06:00) Central Time (US & Canada)",
|
||||
"Central Daylight Time", "America/Chicago" },
|
||||
{ "Easter Island Standard Time", "Easter Island Standard Time", "(UTC-06:00) Easter Island",
|
||||
"Easter Island Daylight Time", "Pacific/Easter" },
|
||||
{ "Central Standard Time (Mexico)", "Central Standard Time (Mexico)",
|
||||
"(UTC-06:00) Guadalajara, Mexico City, Monterrey", "Central Daylight Time (Mexico)",
|
||||
"America/Mexico_City" },
|
||||
{ "Canada Central Standard Time", "Canada Central Standard Time", "(UTC-06:00) Saskatchewan",
|
||||
"Canada Central Daylight Time", "America/Regina" },
|
||||
{ "SA Pacific Standard Time", "SA Pacific Standard Time",
|
||||
"(UTC-05:00) Bogota, Lima, Quito, Rio Branco", "SA Pacific Daylight Time", "America/Bogota" },
|
||||
{ "Eastern Standard Time (Mexico)", "Eastern Standard Time (Mexico)", "(UTC-05:00) Chetumal",
|
||||
"Eastern Daylight Time (Mexico)", "America/Cancun" },
|
||||
{ "Eastern Standard Time", "Eastern Standard Time", "(UTC-05:00) Eastern Time (US & Canada)",
|
||||
"Eastern Daylight Time", "America/New_York" },
|
||||
{ "Haiti Standard Time", "Haiti Standard Time", "(UTC-05:00) Haiti", "Haiti Daylight Time",
|
||||
"America/Port-au-Prince" },
|
||||
{ "Cuba Standard Time", "Cuba Standard Time", "(UTC-05:00) Havana", "Cuba Daylight Time",
|
||||
"America/Havana" },
|
||||
{ "US Eastern Standard Time", "US Eastern Standard Time", "(UTC-05:00) Indiana (East)",
|
||||
"US Eastern Daylight Time", "America/Indianapolis" },
|
||||
{ "Turks And Caicos Standard Time", "Turks and Caicos Standard Time",
|
||||
"(UTC-05:00) Turks and Caicos", "Turks and Caicos Daylight Time", "America/Grand_Turk" },
|
||||
{ "Paraguay Standard Time", "Paraguay Standard Time", "(UTC-04:00) Asuncion",
|
||||
"Paraguay Daylight Time", "America/Asuncion" },
|
||||
{ "Atlantic Standard Time", "Atlantic Standard Time", "(UTC-04:00) Atlantic Time (Canada)",
|
||||
"Atlantic Daylight Time", "America/Halifax" },
|
||||
{ "Venezuela Standard Time", "Venezuela Standard Time", "(UTC-04:00) Caracas",
|
||||
"Venezuela Daylight Time", "America/Caracas" },
|
||||
{ "Central Brazilian Standard Time", "Central Brazilian Standard Time", "(UTC-04:00) Cuiaba",
|
||||
"Central Brazilian Daylight Time", "America/Cuiaba" },
|
||||
{ "SA Western Standard Time", "SA Western Standard Time",
|
||||
"(UTC-04:00) Georgetown, La Paz, Manaus, San Juan", "SA Western Daylight Time",
|
||||
"America/La_Paz" },
|
||||
{ "Pacific SA Standard Time", "Pacific SA Standard Time", "(UTC-04:00) Santiago",
|
||||
"Pacific SA Daylight Time", "America/Santiago" },
|
||||
{ "Newfoundland Standard Time", "Newfoundland Standard Time", "(UTC-03:30) Newfoundland",
|
||||
"Newfoundland Daylight Time", "America/St_Johns" },
|
||||
{ "Tocantins Standard Time", "Tocantins Standard Time", "(UTC-03:00) Araguaina",
|
||||
"Tocantins Daylight Time", "America/Araguaina" },
|
||||
{ "E. South America Standard Time", "E. South America Standard Time", "(UTC-03:00) Brasilia",
|
||||
"E. South America Daylight Time", "America/Sao_Paulo" },
|
||||
{ "SA Eastern Standard Time", "SA Eastern Standard Time", "(UTC-03:00) Cayenne, Fortaleza",
|
||||
"SA Eastern Daylight Time", "America/Cayenne" },
|
||||
{ "Argentina Standard Time", "Argentina Standard Time", "(UTC-03:00) City of Buenos Aires",
|
||||
"Argentina Daylight Time", "America/Buenos_Aires" },
|
||||
{ "Montevideo Standard Time", "Montevideo Standard Time", "(UTC-03:00) Montevideo",
|
||||
"Montevideo Daylight Time", "America/Montevideo" },
|
||||
{ "Magallanes Standard Time", "Magallanes Standard Time", "(UTC-03:00) Punta Arenas",
|
||||
"Magallanes Daylight Time", "America/Punta_Arenas" },
|
||||
{ "Saint Pierre Standard Time", "Saint Pierre Standard Time",
|
||||
"(UTC-03:00) Saint Pierre and Miquelon", "Saint Pierre Daylight Time", "America/Miquelon" },
|
||||
{ "Bahia Standard Time", "Bahia Standard Time", "(UTC-03:00) Salvador", "Bahia Daylight Time",
|
||||
"America/Bahia" },
|
||||
{ "UTC-02", "UTC-02", "(UTC-02:00) Coordinated Universal Time-02", "UTC-02", "Etc/GMT+2" },
|
||||
{ "Greenland Standard Time", "Greenland Standard Time", "(UTC-02:00) Greenland",
|
||||
"Greenland Daylight Time", "America/Godthab" },
|
||||
{ "Mid-Atlantic Standard Time", "Mid-Atlantic Standard Time", "(UTC-02:00) Mid-Atlantic - Old",
|
||||
"Mid-Atlantic Daylight Time", "" },
|
||||
{ "Azores Standard Time", "Azores Standard Time", "(UTC-01:00) Azores", "Azores Daylight Time",
|
||||
"Atlantic/Azores" },
|
||||
{ "Cape Verde Standard Time", "Cabo Verde Standard Time", "(UTC-01:00) Cabo Verde Is.",
|
||||
"Cabo Verde Daylight Time", "Atlantic/Cape_Verde" },
|
||||
{ "UTC", "Coordinated Universal Time", "(UTC) Coordinated Universal Time",
|
||||
"Coordinated Universal Time", "Etc/UTC" },
|
||||
{ "GMT Standard Time", "GMT Standard Time", "(UTC+00:00) Dublin, Edinburgh, Lisbon, London",
|
||||
"GMT Daylight Time", "Europe/London" },
|
||||
{ "Greenwich Standard Time", "Greenwich Standard Time", "(UTC+00:00) Monrovia, Reykjavik",
|
||||
"Greenwich Daylight Time", "Atlantic/Reykjavik" },
|
||||
{ "Sao Tome Standard Time", "Sao Tome Standard Time", "(UTC+00:00) Sao Tome",
|
||||
"Sao Tome Daylight Time", "Africa/Sao_Tome" },
|
||||
{ "Morocco Standard Time", "Morocco Standard Time", "(UTC+01:00) Casablanca",
|
||||
"Morocco Daylight Time", "Africa/Casablanca" },
|
||||
{ "W. Europe Standard Time", "W. Europe Standard Time",
|
||||
"(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna", "W. Europe Daylight Time",
|
||||
"Europe/Berlin" },
|
||||
{ "Central Europe Standard Time", "Central Europe Standard Time",
|
||||
"(UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague",
|
||||
"Central Europe Daylight Time", "Europe/Budapest" },
|
||||
{ "Romance Standard Time", "Romance Standard Time",
|
||||
"(UTC+01:00) Brussels, Copenhagen, Madrid, Paris", "Romance Daylight Time", "Europe/Paris" },
|
||||
{ "Central European Standard Time", "Central European Standard Time",
|
||||
"(UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb", "Central European Daylight Time",
|
||||
"Europe/Warsaw" },
|
||||
{ "W. Central Africa Standard Time", "W. Central Africa Standard Time",
|
||||
"(UTC+01:00) West Central Africa", "W. Central Africa Daylight Time", "Africa/Lagos" },
|
||||
{ "GTB Standard Time", "GTB Standard Time", "(UTC+02:00) Athens, Bucharest",
|
||||
"GTB Daylight Time", "Europe/Bucharest" },
|
||||
{ "Middle East Standard Time", "Middle East Standard Time", "(UTC+02:00) Beirut",
|
||||
"Middle East Daylight Time", "Asia/Beirut" },
|
||||
{ "Egypt Standard Time", "Egypt Standard Time", "(UTC+02:00) Cairo", "Egypt Daylight Time",
|
||||
"Africa/Cairo" },
|
||||
{ "E. Europe Standard Time", "E. Europe Standard Time", "(UTC+02:00) Chisinau",
|
||||
"E. Europe Daylight Time", "Europe/Chisinau" },
|
||||
{ "West Bank Standard Time", "West Bank Gaza Standard Time", "(UTC+02:00) Gaza, Hebron",
|
||||
"West Bank Gaza Daylight Time", "Asia/Hebron" },
|
||||
{ "South Africa Standard Time", "South Africa Standard Time", "(UTC+02:00) Harare, Pretoria",
|
||||
"South Africa Daylight Time", "Africa/Johannesburg" },
|
||||
{ "FLE Standard Time", "FLE Standard Time",
|
||||
"(UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius", "FLE Daylight Time",
|
||||
"Europe/Kiev" },
|
||||
{ "Israel Standard Time", "Jerusalem Standard Time", "(UTC+02:00) Jerusalem",
|
||||
"Jerusalem Daylight Time", "Asia/Jerusalem" },
|
||||
{ "South Sudan Standard Time", "South Sudan Standard Time", "(UTC+02:00) Juba",
|
||||
"South Sudan Daylight Time", "" },
|
||||
{ "Kaliningrad Standard Time", "Russia TZ 1 Standard Time", "(UTC+02:00) Kaliningrad",
|
||||
"Russia TZ 1 Daylight Time", "Europe/Kaliningrad" },
|
||||
{ "Sudan Standard Time", "Sudan Standard Time", "(UTC+02:00) Khartoum", "Sudan Daylight Time",
|
||||
"Africa/Khartoum" },
|
||||
{ "Libya Standard Time", "Libya Standard Time", "(UTC+02:00) Tripoli", "Libya Daylight Time",
|
||||
"Africa/Tripoli" },
|
||||
{ "Namibia Standard Time", "Namibia Standard Time", "(UTC+02:00) Windhoek",
|
||||
"Namibia Daylight Time", "Africa/Windhoek" },
|
||||
{ "Jordan Standard Time", "Jordan Standard Time", "(UTC+03:00) Amman", "Jordan Daylight Time",
|
||||
"Asia/Amman" },
|
||||
{ "Arabic Standard Time", "Arabic Standard Time", "(UTC+03:00) Baghdad", "Arabic Daylight Time",
|
||||
"Asia/Baghdad" },
|
||||
{ "Syria Standard Time", "Syria Standard Time", "(UTC+03:00) Damascus", "Syria Daylight Time",
|
||||
"Asia/Damascus" },
|
||||
{ "Turkey Standard Time", "Turkey Standard Time", "(UTC+03:00) Istanbul",
|
||||
"Turkey Daylight Time", "Europe/Istanbul" },
|
||||
{ "Arab Standard Time", "Arab Standard Time", "(UTC+03:00) Kuwait, Riyadh",
|
||||
"Arab Daylight Time", "Asia/Riyadh" },
|
||||
{ "Belarus Standard Time", "Belarus Standard Time", "(UTC+03:00) Minsk",
|
||||
"Belarus Daylight Time", "Europe/Minsk" },
|
||||
{ "Russian Standard Time", "Russia TZ 2 Standard Time", "(UTC+03:00) Moscow, St. Petersburg",
|
||||
"Russia TZ 2 Daylight Time", "Europe/Moscow" },
|
||||
{ "E. Africa Standard Time", "E. Africa Standard Time", "(UTC+03:00) Nairobi",
|
||||
"E. Africa Daylight Time", "Africa/Nairobi" },
|
||||
{ "Volgograd Standard Time", "Volgograd Standard Time", "(UTC+03:00) Volgograd",
|
||||
"Volgograd Daylight Time", "Europe/Volgograd" },
|
||||
{ "Iran Standard Time", "Iran Standard Time", "(UTC+03:30) Tehran", "Iran Daylight Time",
|
||||
"Asia/Tehran" },
|
||||
{ "Arabian Standard Time", "Arabian Standard Time", "(UTC+04:00) Abu Dhabi, Muscat",
|
||||
"Arabian Daylight Time", "Asia/Dubai" },
|
||||
{ "Astrakhan Standard Time", "Astrakhan Standard Time", "(UTC+04:00) Astrakhan, Ulyanovsk",
|
||||
"Astrakhan Daylight Time", "Europe/Astrakhan" },
|
||||
{ "Azerbaijan Standard Time", "Azerbaijan Standard Time", "(UTC+04:00) Baku",
|
||||
"Azerbaijan Daylight Time", "Asia/Baku" },
|
||||
{ "Russia Time Zone 3", "Russia TZ 3 Standard Time", "(UTC+04:00) Izhevsk, Samara",
|
||||
"Russia TZ 3 Daylight Time", "Europe/Samara" },
|
||||
{ "Mauritius Standard Time", "Mauritius Standard Time", "(UTC+04:00) Port Louis",
|
||||
"Mauritius Daylight Time", "Indian/Mauritius" },
|
||||
{ "Saratov Standard Time", "Saratov Standard Time", "(UTC+04:00) Saratov",
|
||||
"Saratov Daylight Time", "Europe/Saratov" },
|
||||
{ "Georgian Standard Time", "Georgian Standard Time", "(UTC+04:00) Tbilisi",
|
||||
"Georgian Daylight Time", "Asia/Tbilisi" },
|
||||
{ "Caucasus Standard Time", "Caucasus Standard Time", "(UTC+04:00) Yerevan",
|
||||
"Caucasus Daylight Time", "Asia/Yerevan" },
|
||||
{ "Afghanistan Standard Time", "Afghanistan Standard Time", "(UTC+04:30) Kabul",
|
||||
"Afghanistan Daylight Time", "Asia/Kabul" },
|
||||
{ "West Asia Standard Time", "West Asia Standard Time", "(UTC+05:00) Ashgabat, Tashkent",
|
||||
"West Asia Daylight Time", "Asia/Tashkent" },
|
||||
{ "Qyzylorda Standard Time", "Qyzylorda Standard Time", "(UTC+05:00) Astana",
|
||||
"Qyzylorda Daylight Time", "Asia/Qyzylorda" },
|
||||
{ "Ekaterinburg Standard Time", "Russia TZ 4 Standard Time", "(UTC+05:00) Ekaterinburg",
|
||||
"Russia TZ 4 Daylight Time", "Asia/Yekaterinburg" },
|
||||
{ "Pakistan Standard Time", "Pakistan Standard Time", "(UTC+05:00) Islamabad, Karachi",
|
||||
"Pakistan Daylight Time", "Asia/Karachi" },
|
||||
{ "India Standard Time", "India Standard Time",
|
||||
"(UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi", "India Daylight Time", "Asia/Calcutta" },
|
||||
{ "Sri Lanka Standard Time", "Sri Lanka Standard Time", "(UTC+05:30) Sri Jayawardenepura",
|
||||
"Sri Lanka Daylight Time", "Asia/Colombo" },
|
||||
{ "Nepal Standard Time", "Nepal Standard Time", "(UTC+05:45) Kathmandu", "Nepal Daylight Time",
|
||||
"Asia/Katmandu" },
|
||||
{ "Central Asia Standard Time", "Central Asia Standard Time", "(UTC+06:00) Bishkek",
|
||||
"Central Asia Daylight Time", "Asia/Almaty" },
|
||||
{ "Bangladesh Standard Time", "Bangladesh Standard Time", "(UTC+06:00) Dhaka",
|
||||
"Bangladesh Daylight Time", "Asia/Dhaka" },
|
||||
{ "Omsk Standard Time", "Omsk Standard Time", "(UTC+06:00) Omsk", "Omsk Daylight Time",
|
||||
"Asia/Omsk" },
|
||||
{ "Myanmar Standard Time", "Myanmar Standard Time", "(UTC+06:30) Yangon (Rangoon)",
|
||||
"Myanmar Daylight Time", "Asia/Rangoon" },
|
||||
{ "SE Asia Standard Time", "SE Asia Standard Time", "(UTC+07:00) Bangkok, Hanoi, Jakarta",
|
||||
"SE Asia Daylight Time", "Asia/Bangkok" },
|
||||
{ "Altai Standard Time", "Altai Standard Time", "(UTC+07:00) Barnaul, Gorno-Altaysk",
|
||||
"Altai Daylight Time", "Asia/Barnaul" },
|
||||
{ "W. Mongolia Standard Time", "W. Mongolia Standard Time", "(UTC+07:00) Hovd",
|
||||
"W. Mongolia Daylight Time", "Asia/Hovd" },
|
||||
{ "North Asia Standard Time", "Russia TZ 6 Standard Time", "(UTC+07:00) Krasnoyarsk",
|
||||
"Russia TZ 6 Daylight Time", "Asia/Krasnoyarsk" },
|
||||
{ "N. Central Asia Standard Time", "Novosibirsk Standard Time", "(UTC+07:00) Novosibirsk",
|
||||
"Novosibirsk Daylight Time", "Asia/Novosibirsk" },
|
||||
{ "Tomsk Standard Time", "Tomsk Standard Time", "(UTC+07:00) Tomsk", "Tomsk Daylight Time",
|
||||
"Asia/Tomsk" },
|
||||
{ "China Standard Time", "China Standard Time",
|
||||
"(UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi", "China Daylight Time", "Asia/Shanghai" },
|
||||
{ "North Asia East Standard Time", "Russia TZ 7 Standard Time", "(UTC+08:00) Irkutsk",
|
||||
"Russia TZ 7 Daylight Time", "Asia/Irkutsk" },
|
||||
{ "Singapore Standard Time", "Malay Peninsula Standard Time",
|
||||
"(UTC+08:00) Kuala Lumpur, Singapore", "Malay Peninsula Daylight Time", "Asia/Singapore" },
|
||||
{ "W. Australia Standard Time", "W. Australia Standard Time", "(UTC+08:00) Perth",
|
||||
"W. Australia Daylight Time", "Australia/Perth" },
|
||||
{ "Taipei Standard Time", "Taipei Standard Time", "(UTC+08:00) Taipei", "Taipei Daylight Time",
|
||||
"Asia/Taipei" },
|
||||
{ "Ulaanbaatar Standard Time", "Ulaanbaatar Standard Time", "(UTC+08:00) Ulaanbaatar",
|
||||
"Ulaanbaatar Daylight Time", "Asia/Ulaanbaatar" },
|
||||
{ "Aus Central W. Standard Time", "Aus Central W. Standard Time", "(UTC+08:45) Eucla",
|
||||
"Aus Central W. Daylight Time", "Australia/Eucla" },
|
||||
{ "Transbaikal Standard Time", "Transbaikal Standard Time", "(UTC+09:00) Chita",
|
||||
"Transbaikal Daylight Time", "Asia/Chita" },
|
||||
{ "Tokyo Standard Time", "Tokyo Standard Time", "(UTC+09:00) Osaka, Sapporo, Tokyo",
|
||||
"Tokyo Daylight Time", "Asia/Tokyo" },
|
||||
{ "North Korea Standard Time", "North Korea Standard Time", "(UTC+09:00) Pyongyang",
|
||||
"North Korea Daylight Time", "Asia/Pyongyang" },
|
||||
{ "Korea Standard Time", "Korea Standard Time", "(UTC+09:00) Seoul", "Korea Daylight Time",
|
||||
"Asia/Seoul" },
|
||||
{ "Yakutsk Standard Time", "Russia TZ 8 Standard Time", "(UTC+09:00) Yakutsk",
|
||||
"Russia TZ 8 Daylight Time", "Asia/Yakutsk" },
|
||||
{ "Cen. Australia Standard Time", "Cen. Australia Standard Time", "(UTC+09:30) Adelaide",
|
||||
"Cen. Australia Daylight Time", "Australia/Adelaide" },
|
||||
{ "AUS Central Standard Time", "AUS Central Standard Time", "(UTC+09:30) Darwin",
|
||||
"AUS Central Daylight Time", "Australia/Darwin" },
|
||||
{ "E. Australia Standard Time", "E. Australia Standard Time", "(UTC+10:00) Brisbane",
|
||||
"E. Australia Daylight Time", "Australia/Brisbane" },
|
||||
{ "AUS Eastern Standard Time", "AUS Eastern Standard Time",
|
||||
"(UTC+10:00) Canberra, Melbourne, Sydney", "AUS Eastern Daylight Time", "Australia/Sydney" },
|
||||
{ "West Pacific Standard Time", "West Pacific Standard Time", "(UTC+10:00) Guam, Port Moresby",
|
||||
"West Pacific Daylight Time", "Pacific/Port_Moresby" },
|
||||
{ "Tasmania Standard Time", "Tasmania Standard Time", "(UTC+10:00) Hobart",
|
||||
"Tasmania Daylight Time", "Australia/Hobart" },
|
||||
{ "Vladivostok Standard Time", "Russia TZ 9 Standard Time", "(UTC+10:00) Vladivostok",
|
||||
"Russia TZ 9 Daylight Time", "Asia/Vladivostok" },
|
||||
{ "Lord Howe Standard Time", "Lord Howe Standard Time", "(UTC+10:30) Lord Howe Island",
|
||||
"Lord Howe Daylight Time", "Australia/Lord_Howe" },
|
||||
{ "Bougainville Standard Time", "Bougainville Standard Time", "(UTC+11:00) Bougainville Island",
|
||||
"Bougainville Daylight Time", "Pacific/Bougainville" },
|
||||
{ "Russia Time Zone 10", "Russia TZ 10 Standard Time", "(UTC+11:00) Chokurdakh",
|
||||
"Russia TZ 10 Daylight Time", "Asia/Srednekolymsk" },
|
||||
{ "Magadan Standard Time", "Magadan Standard Time", "(UTC+11:00) Magadan",
|
||||
"Magadan Daylight Time", "Asia/Magadan" },
|
||||
{ "Norfolk Standard Time", "Norfolk Standard Time", "(UTC+11:00) Norfolk Island",
|
||||
"Norfolk Daylight Time", "Pacific/Norfolk" },
|
||||
{ "Sakhalin Standard Time", "Sakhalin Standard Time", "(UTC+11:00) Sakhalin",
|
||||
"Sakhalin Daylight Time", "Asia/Sakhalin" },
|
||||
{ "Central Pacific Standard Time", "Central Pacific Standard Time",
|
||||
"(UTC+11:00) Solomon Is., New Caledonia", "Central Pacific Daylight Time",
|
||||
"Pacific/Guadalcanal" },
|
||||
{ "Russia Time Zone 11", "Russia TZ 11 Standard Time",
|
||||
"(UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky", "Russia TZ 11 Daylight Time",
|
||||
"Asia/Kamchatka" },
|
||||
{ "New Zealand Standard Time", "New Zealand Standard Time", "(UTC+12:00) Auckland, Wellington",
|
||||
"New Zealand Daylight Time", "Pacific/Auckland" },
|
||||
{ "UTC+12", "UTC+12", "(UTC+12:00) Coordinated Universal Time+12", "UTC+12", "Etc/GMT-12" },
|
||||
{ "Fiji Standard Time", "Fiji Standard Time", "(UTC+12:00) Fiji", "Fiji Daylight Time",
|
||||
"Pacific/Fiji" },
|
||||
{ "Kamchatka Standard Time", "Kamchatka Standard Time",
|
||||
"(UTC+12:00) Petropavlovsk-Kamchatsky - Old", "Kamchatka Daylight Time", "" },
|
||||
{ "Chatham Islands Standard Time", "Chatham Islands Standard Time",
|
||||
"(UTC+12:45) Chatham Islands", "Chatham Islands Daylight Time", "Pacific/Chatham" },
|
||||
{ "UTC+13", "UTC+13", "(UTC+13:00) Coordinated Universal Time+13", "UTC+13", "Etc/GMT-13" },
|
||||
{ "Tonga Standard Time", "Tonga Standard Time", "(UTC+13:00) Nuku'alofa", "Tonga Daylight Time",
|
||||
"Pacific/Tongatapu" },
|
||||
{ "Samoa Standard Time", "Samoa Standard Time", "(UTC+13:00) Samoa", "Samoa Daylight Time",
|
||||
"Pacific/Apia" },
|
||||
{ "Line Islands Standard Time", "Line Islands Standard Time", "(UTC+14:00) Kiritimati Island",
|
||||
"Line Islands Daylight Time", "Pacific/Kiritimati" },
|
||||
};
|
||||
const size_t TimeZoneNameMapSize = ARRAYSIZE(TimeZoneNameMap);
|
||||
49
winpr/libwinpr/timezone/TimeZoneNameMap.h
Normal file
49
winpr/libwinpr/timezone/TimeZoneNameMap.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Time Zone Name Map
|
||||
*
|
||||
* Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2024 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_TIME_NAME_MAP_H_
|
||||
#define WINPR_TIME_NAME_MAP_H_
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TIME_ZONE_NAME_ID,
|
||||
TIME_ZONE_NAME_STANDARD,
|
||||
TIME_ZONE_NAME_DISPLAY,
|
||||
TIME_ZONE_NAME_DAYLIGHT,
|
||||
TIME_ZONE_NAME_IANA,
|
||||
} TimeZoneNameType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* Id;
|
||||
const char* StandardName;
|
||||
const char* DisplayName;
|
||||
const char* DaylightName;
|
||||
const char* Iana;
|
||||
} TimeZoneNameMapEntry;
|
||||
|
||||
extern const TimeZoneNameMapEntry TimeZoneNameMap[];
|
||||
extern const size_t TimeZoneNameMapSize;
|
||||
|
||||
const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type);
|
||||
|
||||
#endif
|
||||
149
winpr/libwinpr/timezone/TimeZoneNameMapUtils.c
Normal file
149
winpr/libwinpr/timezone/TimeZoneNameMapUtils.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Time Zone Name Map Utils
|
||||
*
|
||||
* Copyright 2024 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2024 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <winpr/config.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(WITH_TIMEZONE_ICU)
|
||||
#include <unicode/ucal.h>
|
||||
#else
|
||||
#include "WindowsZones.h"
|
||||
#endif
|
||||
|
||||
#include "TimeZoneNameMap.h"
|
||||
|
||||
static const char* return_type(const TimeZoneNameMapEntry* entry, TimeZoneNameType type)
|
||||
{
|
||||
WINPR_ASSERT(entry);
|
||||
switch (type)
|
||||
{
|
||||
case TIME_ZONE_NAME_IANA:
|
||||
return entry->Iana;
|
||||
case TIME_ZONE_NAME_ID:
|
||||
return entry->Id;
|
||||
case TIME_ZONE_NAME_STANDARD:
|
||||
return entry->StandardName;
|
||||
case TIME_ZONE_NAME_DISPLAY:
|
||||
return entry->DisplayName;
|
||||
case TIME_ZONE_NAME_DAYLIGHT:
|
||||
return entry->DaylightName;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_TIMEZONE_ICU)
|
||||
static char* get_wzid_icu(const UChar* utzid, size_t utzid_len)
|
||||
{
|
||||
char* res = NULL;
|
||||
UErrorCode error = U_ZERO_ERROR;
|
||||
|
||||
int32_t rc = ucal_getWindowsTimeZoneID(utzid, utzid_len, NULL, 0, &error);
|
||||
if ((error == U_BUFFER_OVERFLOW_ERROR) && (rc > 0))
|
||||
{
|
||||
rc++; // make space for '\0'
|
||||
UChar* wzid = calloc((size_t)rc + 1, sizeof(UChar));
|
||||
if (wzid)
|
||||
{
|
||||
UErrorCode error2 = U_ZERO_ERROR;
|
||||
int32_t rc2 = ucal_getWindowsTimeZoneID(utzid, utzid_len, wzid, rc, &error2);
|
||||
if (U_SUCCESS(error2) && (rc2 > 0))
|
||||
res = ConvertWCharNToUtf8Alloc(wzid, (size_t)rc, NULL);
|
||||
free(wzid);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static char* get(const char* iana)
|
||||
{
|
||||
size_t utzid_len = 0;
|
||||
UChar* utzid = ConvertUtf8ToWCharAlloc(iana, &utzid_len);
|
||||
if (!utzid)
|
||||
return NULL;
|
||||
|
||||
char* wzid = get_wzid_icu(utzid, utzid_len);
|
||||
free(utzid);
|
||||
return wzid;
|
||||
}
|
||||
|
||||
static const char* map_fallback(const char* iana, TimeZoneNameType type)
|
||||
{
|
||||
const char* res = NULL;
|
||||
char* wzid = get(iana);
|
||||
if (!wzid)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
||||
if (strcmp(wzid, entry->Id) == 0)
|
||||
{
|
||||
res = return_type(entry, type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(wzid);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
static const char* map_fallback(const char* iana, TimeZoneNameType type)
|
||||
{
|
||||
if (!iana)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < WindowsTimeZoneIdTableNrElements; x++)
|
||||
{
|
||||
const WINDOWS_TZID_ENTRY* const entry = &WindowsTimeZoneIdTable[x];
|
||||
if (strcmp(entry->tzid, iana) == 0)
|
||||
return entry->windows;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type)
|
||||
{
|
||||
if (!iana)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
||||
if (strcmp(iana, entry->Iana) == 0)
|
||||
return return_type(entry, type);
|
||||
}
|
||||
|
||||
const char* wzid = map_fallback(iana, type);
|
||||
if (!wzid)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
||||
{
|
||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
||||
if (strcmp(wzid, entry->Id) == 0)
|
||||
return return_type(entry, type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Automatically generated with scripts/TimeZones.csx
|
||||
*/
|
||||
|
||||
#ifndef WINPR_TIME_ZONES_H_
|
||||
#define WINPR_TIME_ZONES_H_
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT64 TicksStart;
|
||||
UINT64 TicksEnd;
|
||||
INT32 DaylightDelta;
|
||||
SYSTEMTIME StandardDate;
|
||||
SYSTEMTIME DaylightDate;
|
||||
} TIME_ZONE_RULE_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* Id;
|
||||
INT32 Bias;
|
||||
BOOL SupportsDST;
|
||||
const char* DisplayName;
|
||||
const char* StandardName;
|
||||
const char* DaylightName;
|
||||
const TIME_ZONE_RULE_ENTRY* RuleTable;
|
||||
UINT32 RuleTableCount;
|
||||
} TIME_ZONE_ENTRY;
|
||||
|
||||
extern const TIME_ZONE_ENTRY TimeZoneTable[];
|
||||
extern const size_t TimeZoneTableNrElements;
|
||||
|
||||
#endif /* WINPR_TIME_ZONES_H_ */
|
||||
@@ -29,29 +29,20 @@
|
||||
|
||||
#define TAG WINPR_TAG("timezone")
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#include "TimeZoneNameMap.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "TimeZones.h"
|
||||
#include "WindowsZones.h"
|
||||
|
||||
static UINT64 winpr_windows_gmtime(void)
|
||||
{
|
||||
time_t unix_time = 0;
|
||||
UINT64 windows_time = 0;
|
||||
time(&unix_time);
|
||||
|
||||
if (unix_time < 0)
|
||||
return 0;
|
||||
|
||||
windows_time = (UINT64)unix_time;
|
||||
windows_time *= 10000000;
|
||||
windows_time += 621355968000000000ULL;
|
||||
return windows_time;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
static char* winpr_read_unix_timezone_identifier_from_file(FILE* fp)
|
||||
{
|
||||
const INT CHUNK_SIZE = 32;
|
||||
@@ -60,7 +51,7 @@ static char* winpr_read_unix_timezone_identifier_from_file(FILE* fp)
|
||||
INT64 length = CHUNK_SIZE;
|
||||
char* tzid = NULL;
|
||||
|
||||
tzid = (char*)malloc(length);
|
||||
tzid = (char*)malloc((size_t)length);
|
||||
if (!tzid)
|
||||
return NULL;
|
||||
|
||||
@@ -266,49 +257,19 @@ static char* winpr_get_unix_timezone_identifier_from_file(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL winpr_match_unix_timezone_identifier_with_list(const char* tzid, const char* list)
|
||||
static char* winpr_time_zone_from_env(void)
|
||||
{
|
||||
char* p = NULL;
|
||||
char* list_copy = NULL;
|
||||
char* context = NULL;
|
||||
|
||||
list_copy = _strdup(list);
|
||||
|
||||
if (!list_copy)
|
||||
return FALSE;
|
||||
|
||||
p = strtok_s(list_copy, " ", &context);
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
if (strcmp(p, tzid) == 0)
|
||||
{
|
||||
free(list_copy);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
p = strtok_s(NULL, " ", &context);
|
||||
}
|
||||
|
||||
free(list_copy);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(void)
|
||||
{
|
||||
char* tzid = NULL;
|
||||
char* ntzid = NULL;
|
||||
LPCSTR tz = "TZ";
|
||||
char* tzid = NULL;
|
||||
|
||||
DWORD nSize = GetEnvironmentVariableA(tz, NULL, 0);
|
||||
if (nSize)
|
||||
if (nSize > 0)
|
||||
{
|
||||
tzid = (char*)malloc(nSize);
|
||||
tzid = (char*)calloc(nSize, sizeof(char));
|
||||
if (!tzid)
|
||||
goto fail;
|
||||
if (!GetEnvironmentVariableA(tz, tzid, nSize))
|
||||
{
|
||||
free(tzid);
|
||||
tzid = NULL;
|
||||
}
|
||||
goto fail;
|
||||
else if (tzid[0] == ':')
|
||||
{
|
||||
/* Remove leading colon, see tzset(3) */
|
||||
@@ -316,167 +277,253 @@ static TIME_ZONE_ENTRY* winpr_detect_windows_time_zone(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (tzid == NULL)
|
||||
tzid = winpr_get_unix_timezone_identifier_from_file();
|
||||
return tzid;
|
||||
|
||||
if (tzid == NULL)
|
||||
{
|
||||
tzid = winpr_get_timezone_from_link(NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* zipath = "/usr/share/zoneinfo/";
|
||||
char buf[1024] = { 0 };
|
||||
const char* links[] = { buf };
|
||||
|
||||
if (tzid[0] == '/')
|
||||
{
|
||||
/* Full path given in TZ */
|
||||
links[0] = tzid;
|
||||
}
|
||||
else
|
||||
snprintf(buf, ARRAYSIZE(buf), "%s%s", zipath, tzid);
|
||||
|
||||
ntzid = winpr_get_timezone_from_link(links, 1);
|
||||
if (ntzid != NULL)
|
||||
{
|
||||
free(tzid);
|
||||
tzid = ntzid;
|
||||
}
|
||||
}
|
||||
|
||||
if (tzid == NULL)
|
||||
return NULL;
|
||||
|
||||
WLog_INFO(TAG, "tzid: %s", tzid);
|
||||
|
||||
for (size_t i = 0; i < TimeZoneTableNrElements; i++)
|
||||
{
|
||||
const TIME_ZONE_ENTRY* tze = &TimeZoneTable[i];
|
||||
|
||||
for (size_t j = 0; j < WindowsTimeZoneIdTableNrElements; j++)
|
||||
{
|
||||
const WINDOWS_TZID_ENTRY* wzid = &WindowsTimeZoneIdTable[j];
|
||||
|
||||
if (strcmp(tze->Id, wzid->windows) != 0)
|
||||
continue;
|
||||
|
||||
if (winpr_match_unix_timezone_identifier_with_list(tzid, wzid->tzid))
|
||||
{
|
||||
TIME_ZONE_ENTRY* ctimezone = (TIME_ZONE_ENTRY*)malloc(sizeof(TIME_ZONE_ENTRY));
|
||||
free(tzid);
|
||||
|
||||
if (!ctimezone)
|
||||
return NULL;
|
||||
|
||||
*ctimezone = TimeZoneTable[i];
|
||||
return ctimezone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "Unable to find a match for unix timezone: %s", tzid);
|
||||
fail:
|
||||
free(tzid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const TIME_ZONE_RULE_ENTRY*
|
||||
winpr_get_current_time_zone_rule(const TIME_ZONE_RULE_ENTRY* rules, UINT32 count)
|
||||
static char* winpr_translate_time_zone(const char* tzid)
|
||||
{
|
||||
UINT64 windows_time = 0;
|
||||
windows_time = winpr_windows_gmtime();
|
||||
const char* zipath = "/usr/share/zoneinfo/";
|
||||
char* buf = NULL;
|
||||
const char* links[] = { buf };
|
||||
|
||||
for (UINT32 i = 0; i < count; i++)
|
||||
if (!tzid)
|
||||
return NULL;
|
||||
|
||||
if (tzid[0] == '/')
|
||||
{
|
||||
if ((rules[i].TicksStart >= windows_time) && (windows_time >= rules[i].TicksEnd))
|
||||
{
|
||||
/*WLog_ERR(TAG, "Got rule %" PRIu32 " from table at %p with count %"PRIu32"", i,
|
||||
* (void*) rules, count);*/
|
||||
return &rules[i];
|
||||
}
|
||||
/* Full path given in TZ */
|
||||
links[0] = tzid;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t bsize = 0;
|
||||
winpr_asprintf(&buf, &bsize, "%s%s", zipath, tzid);
|
||||
links[0] = buf;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "Unable to get current timezone rule");
|
||||
return NULL;
|
||||
char* ntzid = winpr_get_timezone_from_link(links, 1);
|
||||
free(buf);
|
||||
return ntzid;
|
||||
}
|
||||
|
||||
static char* winpr_guess_time_zone(void)
|
||||
{
|
||||
char* tzid = winpr_time_zone_from_env();
|
||||
if (tzid)
|
||||
goto end;
|
||||
tzid = winpr_get_unix_timezone_identifier_from_file();
|
||||
if (tzid)
|
||||
goto end;
|
||||
tzid = winpr_get_timezone_from_link(NULL, 0);
|
||||
if (tzid)
|
||||
goto end;
|
||||
|
||||
end:
|
||||
{
|
||||
char* ntzid = winpr_translate_time_zone(tzid);
|
||||
if (ntzid)
|
||||
{
|
||||
free(tzid);
|
||||
return ntzid;
|
||||
}
|
||||
return tzid;
|
||||
}
|
||||
}
|
||||
|
||||
static SYSTEMTIME tm2systemtime(const struct tm* t)
|
||||
{
|
||||
SYSTEMTIME st = { 0 };
|
||||
|
||||
if (t)
|
||||
{
|
||||
st.wYear = (WORD)1900 + t->tm_year;
|
||||
st.wMonth = (WORD)t->tm_mon;
|
||||
st.wDay = (WORD)t->tm_mday;
|
||||
st.wDayOfWeek = (WORD)t->tm_wday;
|
||||
st.wHour = (WORD)t->tm_hour;
|
||||
st.wMinute = (WORD)t->tm_min;
|
||||
st.wSecond = (WORD)t->tm_sec;
|
||||
st.wMilliseconds = 0;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
static LONG get_gmtoff_min(struct tm* t)
|
||||
{
|
||||
WINPR_ASSERT(t);
|
||||
return -t->tm_gmtoff / 60l;
|
||||
}
|
||||
|
||||
static struct tm next_day(const struct tm* start)
|
||||
{
|
||||
struct tm cur = *start;
|
||||
cur.tm_hour = 0;
|
||||
cur.tm_min = 0;
|
||||
cur.tm_sec = 0;
|
||||
cur.tm_isdst = -1;
|
||||
cur.tm_mday++;
|
||||
const time_t t = mktime(&cur);
|
||||
localtime_r(&t, &cur);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct tm adjust_time(const struct tm* start, int hour, int minute)
|
||||
{
|
||||
struct tm cur = *start;
|
||||
cur.tm_hour = hour;
|
||||
cur.tm_min = minute;
|
||||
cur.tm_sec = 0;
|
||||
cur.tm_isdst = -1;
|
||||
const time_t t = mktime(&cur);
|
||||
localtime_r(&t, &cur);
|
||||
return cur;
|
||||
}
|
||||
|
||||
static SYSTEMTIME get_transition_time(const struct tm* start, BOOL toDst)
|
||||
{
|
||||
BOOL toggled = FALSE;
|
||||
struct tm first = adjust_time(start, 0, 0);
|
||||
for (int hour = 0; hour < 24; hour++)
|
||||
{
|
||||
for (int minute = 0; minute < 60; minute++)
|
||||
{
|
||||
struct tm cur = adjust_time(start, hour, minute);
|
||||
if (cur.tm_isdst != first.tm_isdst)
|
||||
toggled = TRUE;
|
||||
|
||||
if (toggled)
|
||||
{
|
||||
if (toDst && (cur.tm_isdst > 0))
|
||||
return tm2systemtime(&cur);
|
||||
else if (!toDst && (cur.tm_isdst == 0))
|
||||
return tm2systemtime(&cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tm2systemtime(start);
|
||||
}
|
||||
|
||||
static BOOL get_transition_date(const struct tm* start, BOOL toDst, SYSTEMTIME* pdate)
|
||||
{
|
||||
WINPR_ASSERT(start);
|
||||
WINPR_ASSERT(pdate);
|
||||
|
||||
*pdate = tm2systemtime(NULL);
|
||||
|
||||
if (start->tm_isdst < 0)
|
||||
return FALSE;
|
||||
|
||||
BOOL val = start->tm_isdst > 0; // the year starts with DST or not
|
||||
BOOL toggled = FALSE;
|
||||
struct tm cur = *start;
|
||||
for (int day = 1; day <= 365; day++)
|
||||
{
|
||||
cur = next_day(&cur);
|
||||
const BOOL curDst = (cur.tm_isdst > 0);
|
||||
if ((val != curDst) && !toggled)
|
||||
toggled = TRUE;
|
||||
|
||||
if (toggled)
|
||||
{
|
||||
if (toDst && curDst)
|
||||
{
|
||||
*pdate = get_transition_time(&cur, toDst);
|
||||
return TRUE;
|
||||
}
|
||||
if (!toDst && !curDst)
|
||||
{
|
||||
*pdate = get_transition_time(&cur, toDst);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static LONG get_bias(const struct tm* start, BOOL dstBias)
|
||||
{
|
||||
if ((start->tm_isdst > 0) && dstBias)
|
||||
return get_gmtoff_min(start);
|
||||
if ((start->tm_isdst == 0) && !dstBias)
|
||||
return get_gmtoff_min(start);
|
||||
if (start->tm_isdst < 0)
|
||||
return get_gmtoff_min(start);
|
||||
|
||||
struct tm cur = *start;
|
||||
for (int day = 1; day <= 365; day++)
|
||||
{
|
||||
cur = next_day(&cur);
|
||||
if ((cur.tm_isdst > 0) && dstBias)
|
||||
return get_gmtoff_min(&cur);
|
||||
else if ((cur.tm_isdst == 0) && !dstBias)
|
||||
return get_gmtoff_min(&cur);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
|
||||
{
|
||||
time_t t = 0;
|
||||
struct tm tres = { 0 };
|
||||
TIME_ZONE_ENTRY* dtz = NULL;
|
||||
const char* defaultName = "Client Local Time";
|
||||
DWORD res = TIME_ZONE_ID_UNKNOWN;
|
||||
const TIME_ZONE_INFORMATION empty = { 0 };
|
||||
LPTIME_ZONE_INFORMATION tz = lpTimeZoneInformation;
|
||||
|
||||
WINPR_ASSERT(tz);
|
||||
|
||||
*tz = empty;
|
||||
ConvertUtf8ToWChar(defaultName, tz->StandardName, ARRAYSIZE(tz->StandardName));
|
||||
|
||||
t = time(NULL);
|
||||
char* tzid = winpr_guess_time_zone();
|
||||
|
||||
const time_t t = time(NULL);
|
||||
struct tm tres = { 0 };
|
||||
struct tm* local_time = localtime_r(&t, &tres);
|
||||
if (!local_time)
|
||||
goto out_error;
|
||||
|
||||
#ifdef WINPR_HAVE_TM_GMTOFF
|
||||
tz->Bias = get_bias(local_time, FALSE);
|
||||
if (local_time->tm_isdst >= 0)
|
||||
{
|
||||
long bias = -(local_time->tm_gmtoff / 60L);
|
||||
|
||||
if (bias > INT32_MAX)
|
||||
bias = INT32_MAX;
|
||||
|
||||
tz->Bias = (LONG)bias;
|
||||
}
|
||||
#endif
|
||||
dtz = winpr_detect_windows_time_zone();
|
||||
|
||||
if (dtz != NULL)
|
||||
{
|
||||
WLog_DBG(TAG, "tz: Bias=%" PRId32 " sn='%s' dln='%s'", dtz->Bias, dtz->StandardName,
|
||||
dtz->DaylightName);
|
||||
|
||||
tz->Bias = dtz->Bias;
|
||||
|
||||
if (ConvertUtf8ToWChar(dtz->StandardName, tz->StandardName, ARRAYSIZE(tz->StandardName)) <
|
||||
0)
|
||||
{
|
||||
WLog_ERR(TAG, "StandardName conversion failed - using default");
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (ConvertUtf8ToWChar(dtz->DaylightName, tz->DaylightName, ARRAYSIZE(tz->DaylightName)) <
|
||||
0)
|
||||
{
|
||||
WLog_ERR(TAG, "DaylightName conversion failed - using default");
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if ((dtz->SupportsDST) && (dtz->RuleTableCount > 0))
|
||||
{
|
||||
const TIME_ZONE_RULE_ENTRY* rule =
|
||||
winpr_get_current_time_zone_rule(dtz->RuleTable, dtz->RuleTableCount);
|
||||
|
||||
if (rule != NULL)
|
||||
{
|
||||
tz->DaylightBias = -rule->DaylightDelta;
|
||||
tz->StandardDate = rule->StandardDate;
|
||||
tz->DaylightDate = rule->DaylightDate;
|
||||
}
|
||||
}
|
||||
|
||||
free(dtz);
|
||||
/* 1 ... TIME_ZONE_ID_STANDARD
|
||||
* 2 ... TIME_ZONE_ID_DAYLIGHT */
|
||||
return local_time->tm_isdst ? 2 : 1;
|
||||
/* DST bias is the difference between standard time and DST in minutes */
|
||||
const LONG d = get_bias(local_time, TRUE);
|
||||
tz->DaylightBias = -1 * labs(tz->Bias - d);
|
||||
get_transition_date(local_time, FALSE, &tz->StandardDate);
|
||||
get_transition_date(local_time, TRUE, &tz->DaylightDate);
|
||||
}
|
||||
|
||||
ConvertUtf8ToWChar(local_time->tm_zone, tz->StandardName, ARRAYSIZE(tz->StandardName));
|
||||
|
||||
const char* winId = TimeZoneIanaToWindows(tzid, TIME_ZONE_NAME_ID);
|
||||
if (winId)
|
||||
{
|
||||
const char* winStd = TimeZoneIanaToWindows(tzid, TIME_ZONE_NAME_STANDARD);
|
||||
const char* winDst = TimeZoneIanaToWindows(tzid, TIME_ZONE_NAME_DAYLIGHT);
|
||||
|
||||
ConvertUtf8ToWChar(winStd, tz->StandardName, ARRAYSIZE(tz->StandardName));
|
||||
ConvertUtf8ToWChar(winDst, tz->DaylightName, ARRAYSIZE(tz->DaylightName));
|
||||
|
||||
res = (local_time->tm_isdst) ? TIME_ZONE_ID_DAYLIGHT : TIME_ZONE_ID_STANDARD;
|
||||
}
|
||||
|
||||
/* could not detect timezone, use computed bias from tm_gmtoff */
|
||||
WLog_DBG(TAG, "tz not found, using computed bias %" PRId32 ".", tz->Bias);
|
||||
out_error:
|
||||
free(dtz);
|
||||
if (ConvertUtf8ToWChar("Client Local Time", tz->StandardName, ARRAYSIZE(tz->StandardName)) <= 0)
|
||||
WLog_WARN(TAG, "Failed to set default timezone name");
|
||||
memcpy(tz->DaylightName, tz->StandardName, sizeof(tz->DaylightName));
|
||||
return 0; /* TIME_ZONE_ID_UNKNOWN */
|
||||
free(tzid);
|
||||
switch (res)
|
||||
{
|
||||
case TIME_ZONE_ID_DAYLIGHT:
|
||||
case TIME_ZONE_ID_STANDARD:
|
||||
WLog_DBG(TAG, "tz: Bias=%" PRId32 " sn='%s' dln='%s'", tz->Bias, tz->StandardName,
|
||||
tz->DaylightName);
|
||||
break;
|
||||
default:
|
||||
WLog_DBG(TAG, "tz not found, using computed bias %" PRId32 ".", tz->Bias);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation)
|
||||
@@ -529,8 +576,28 @@ BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformati
|
||||
|
||||
DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION pTimeZoneInformation)
|
||||
{
|
||||
WINPR_UNUSED(pTimeZoneInformation);
|
||||
return 0;
|
||||
TIME_ZONE_INFORMATION tz = { 0 };
|
||||
const DWORD rc = GetTimeZoneInformation(&tz);
|
||||
|
||||
WINPR_ASSERT(pTimeZoneInformation);
|
||||
pTimeZoneInformation->Bias = tz.Bias;
|
||||
memcpy(pTimeZoneInformation->StandardName, tz.StandardName,
|
||||
MIN(sizeof(tz.StandardName), sizeof(pTimeZoneInformation->StandardName)));
|
||||
pTimeZoneInformation->StandardDate = tz.StandardDate;
|
||||
pTimeZoneInformation->StandardBias = tz.StandardBias;
|
||||
|
||||
memcpy(pTimeZoneInformation->DaylightName, tz.DaylightName,
|
||||
MIN(sizeof(tz.DaylightName), sizeof(pTimeZoneInformation->DaylightName)));
|
||||
pTimeZoneInformation->DaylightDate = tz.DaylightDate;
|
||||
pTimeZoneInformation->DaylightBias = tz.DaylightBias;
|
||||
|
||||
memcpy(pTimeZoneInformation->TimeZoneKeyName, tz.StandardName,
|
||||
MIN(sizeof(tz.StandardName), sizeof(pTimeZoneInformation->TimeZoneKeyName)));
|
||||
|
||||
/* https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information
|
||||
*/
|
||||
pTimeZoneInformation->DynamicDaylightTimeDisabled = FALSE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL SetDynamicTimeZoneInformation(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation)
|
||||
|
||||
Reference in New Issue
Block a user