diff options
author | Abseil Team <absl-team@google.com> | 2023-05-22 12:38:15 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-05-22 12:40:20 -0700 |
commit | 02d1f5e18bb12d9aecade624eb339c319fd866d4 (patch) | |
tree | ff8dd4905dc6ec00ad50d33307529d53eb283088 | |
parent | 25d7c2aeaf22488cafb15cc703e0cb456beb47fa (diff) |
Import of CCTZ from GitHub.
PiperOrigin-RevId: 534150392
Change-Id: I4c0c111202178031e08d9edad3a4501800d924f0
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_format_test.cc | 3 | ||||
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_lookup.cc | 124 |
2 files changed, 124 insertions, 3 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index 7a03e7d2..4a6c71f1 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -221,7 +221,8 @@ TEST(Format, LocaleSpecific) { TestFormatSpecifier(tp, tz, "%B", "January"); // %c should at least produce the numeric year and time-of-day. - const std::string s = format("%c", tp, utc_time_zone()); + const std::string s = + absl::time_internal::cctz::format("%c", tp, utc_time_zone()); EXPECT_THAT(s, testing::HasSubstr("1970")); EXPECT_THAT(s, testing::HasSubstr("00:00:00")); diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc index f6983aeb..68084ce2 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -35,6 +35,19 @@ #include <zircon/types.h> #endif +#if defined(_WIN32) +#include <sdkddkver.h> +// Include only when the SDK is for Windows 10 (and later), and the binary is +// targeted for Windows XP and later. +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +#include <roapi.h> +#include <tchar.h> +#include <wchar.h> +#include <windows.globalization.h> +#include <windows.h> +#endif +#endif + #include <cstdlib> #include <cstring> #include <string> @@ -47,8 +60,8 @@ ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { -#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21 namespace { +#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21 // Android 'L' removes __system_property_get() from the NDK, however // it is still a hidden symbol in libc so we use dlsym() to access it. // See Chromium's base/sys_info_android.cc for a similar example. @@ -72,9 +85,83 @@ int __system_property_get(const char* name, char* value) { static property_get_func system_property_get = LoadSystemPropertyGet(); return system_property_get ? system_property_get(name, value) : -1; } +#endif -} // namespace +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) +// Calls the WinRT Calendar.GetTimeZone method to obtain the IANA ID of the +// local time zone. Returns an empty vector in case of an error. +std::string win32_local_time_zone(const HMODULE combase) { + std::string result; + const auto ro_activate_instance = + reinterpret_cast<decltype(&RoActivateInstance)>( + GetProcAddress(combase, "RoActivateInstance")); + if (!ro_activate_instance) { + return result; + } + const auto windows_create_string_reference = + reinterpret_cast<decltype(&WindowsCreateStringReference)>( + GetProcAddress(combase, "WindowsCreateStringReference")); + if (!windows_create_string_reference) { + return result; + } + const auto windows_delete_string = + reinterpret_cast<decltype(&WindowsDeleteString)>( + GetProcAddress(combase, "WindowsDeleteString")); + if (!windows_delete_string) { + return result; + } + const auto windows_get_string_raw_buffer = + reinterpret_cast<decltype(&WindowsGetStringRawBuffer)>( + GetProcAddress(combase, "WindowsGetStringRawBuffer")); + if (!windows_get_string_raw_buffer) { + return result; + } + + // The string returned by WindowsCreateStringReference doesn't need to be + // deleted. + HSTRING calendar_class_id; + HSTRING_HEADER calendar_class_id_header; + HRESULT hr = windows_create_string_reference( + RuntimeClass_Windows_Globalization_Calendar, + sizeof(RuntimeClass_Windows_Globalization_Calendar) / sizeof(wchar_t) - 1, + &calendar_class_id_header, &calendar_class_id); + if (FAILED(hr)) { + return result; + } + + IInspectable* calendar; + hr = ro_activate_instance(calendar_class_id, &calendar); + if (FAILED(hr)) { + return result; + } + + ABI::Windows::Globalization::ITimeZoneOnCalendar* time_zone; + hr = calendar->QueryInterface(IID_PPV_ARGS(&time_zone)); + if (FAILED(hr)) { + calendar->Release(); + return result; + } + + HSTRING tz_hstr; + hr = time_zone->GetTimeZone(&tz_hstr); + if (SUCCEEDED(hr)) { + UINT32 wlen; + const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen); + if (tz_wstr) { + const int size = WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, nullptr, + 0, nullptr, nullptr); + result.resize(size); + WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, &result[0], size, nullptr, + nullptr); + } + windows_delete_string(tz_hstr); + } + time_zone->Release(); + calendar->Release(); + return result; +} #endif +} // namespace std::string time_zone::name() const { return effective_impl().Name(); } @@ -190,6 +277,39 @@ time_zone local_time_zone() { zone = primary_tz.c_str(); } #endif +#if defined(_WIN32_WINNT_WIN10) && (_WIN32_WINNT >= _WIN32_WINNT_WINXP) + // Use the WinRT Calendar class to get the local time zone. This feature is + // available on Windows 10 and later. The library is dynamically linked to + // maintain binary compatibility with Windows XP - Windows 7. On Windows 8, + // The combase.dll API functions are available but the RoActivateInstance + // call will fail for the Calendar class. + std::string winrt_tz; + const HMODULE combase = + LoadLibraryEx(_T("combase.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (combase) { + const auto ro_initialize = reinterpret_cast<decltype(&::RoInitialize)>( + GetProcAddress(combase, "RoInitialize")); + const auto ro_uninitialize = reinterpret_cast<decltype(&::RoUninitialize)>( + GetProcAddress(combase, "RoUninitialize")); + if (ro_initialize && ro_uninitialize) { + const HRESULT hr = ro_initialize(RO_INIT_MULTITHREADED); + // RPC_E_CHANGED_MODE means that a previous RoInitialize call specified + // a different concurrency model. The WinRT runtime is initialized and + // should work for our purpose here, but we should *not* call + // RoUninitialize because it's a failure. + if (SUCCEEDED(hr) || hr == RPC_E_CHANGED_MODE) { + winrt_tz = win32_local_time_zone(combase); + if (SUCCEEDED(hr)) { + ro_uninitialize(); + } + } + } + FreeLibrary(combase); + } + if (!winrt_tz.empty()) { + zone = winrt_tz.c_str(); + } +#endif // Allow ${TZ} to override to default zone. char* tz_env = nullptr; |