From 2fb481f3dbed06dc71190733cc47780d8cdddbe1 Mon Sep 17 00:00:00 2001 From: Marek Biolik Date: Fri, 18 Oct 2024 11:49:49 +0200 Subject: [PATCH] [NPLB] Support SetTimeZone extension on win and Xbox --- starboard/nplb/time_zone_get_current_test.cc | 146 +++++++++++------- starboard/nplb/time_zone_get_name_test.cc | 4 + .../shared/win32/system_get_extensions.cc | 5 + starboard/shared/win32/time_zone.cc | 75 +++++++++ starboard/shared/win32/time_zone.h | 28 ++++ starboard/win/win32/BUILD.gn | 1 + 6 files changed, 200 insertions(+), 59 deletions(-) create mode 100644 starboard/shared/win32/time_zone.cc create mode 100644 starboard/shared/win32/time_zone.h diff --git a/starboard/nplb/time_zone_get_current_test.cc b/starboard/nplb/time_zone_get_current_test.cc index b18d5de27641..e4f5a27b1d0c 100644 --- a/starboard/nplb/time_zone_get_current_test.cc +++ b/starboard/nplb/time_zone_get_current_test.cc @@ -13,14 +13,58 @@ // limitations under the License. #include "starboard/extension/time_zone.h" +#include "starboard/nplb/time_constants.h" #include "starboard/system.h" #include "starboard/time_zone.h" #include "testing/gtest/include/gtest/gtest.h" +#include +#include + namespace starboard { namespace nplb { namespace { +struct TimeZoneWithExpectValue { + TimeZoneWithExpectValue(std::string timeZoneName_, + SbTimeZone expectedStandardValue_, + SbTimeZone expectedDaylightValue_) + : timeZoneName{timeZoneName_}, + expectedStandardValue{expectedStandardValue_}, + expectedDaylightValue{expectedDaylightValue_} {} + + std::string timeZoneName; + + SbTimeZone expectedStandardValue; + SbTimeZone expectedDaylightValue; +}; + +class SbTimeZoneGetCurrentSetTimeZoneTest + : public testing::Test, + public testing::WithParamInterface { + protected: + void SetUp() override { + time_zone_extension = static_cast( + SbSystemGetExtension(kStarboardExtensionTimeZoneName)); + if (!time_zone_extension) { + GTEST_SKIP() + << "Skipping test for platform with missing Time Zone Extension."; + } + ASSERT_STREQ(time_zone_extension->name, kStarboardExtensionTimeZoneName); + ASSERT_EQ(time_zone_extension->version, 1u); + savedTimeZone = SbTimeZoneGetName(); + } + + void TearDown() override { + if (time_zone_extension) { + time_zone_extension->SetTimeZone(savedTimeZone.c_str()); + } + } + + std::string savedTimeZone; + const StarboardExtensionTimeZoneApi* time_zone_extension; +}; + TEST(SbTimeZoneGetCurrentTest, IsKindOfSane) { SbTimeZone zone = SbTimeZoneGetCurrent(); @@ -34,68 +78,52 @@ TEST(SbTimeZoneGetCurrentTest, IsKindOfSane) { // ... and +24 hours from the Prime Meridian, inclusive EXPECT_LE(zone, 24 * 60); +} - static auto const* time_zone_extension = - static_cast( - SbSystemGetExtension(kStarboardExtensionTimeZoneName)); - if (time_zone_extension) { - ASSERT_STREQ(time_zone_extension->name, kStarboardExtensionTimeZoneName); - ASSERT_EQ(time_zone_extension->version, 1u); - time_zone_extension->SetTimeZone("UTC"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 0); - - // Atlantic time zone, UTC−04:00 - time_zone_extension->SetTimeZone("America/Puerto_Rico"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 240); - - // Eastern time zone, UTC−05:00 - time_zone_extension->SetTimeZone("America/New_York"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 300); - - time_zone_extension->SetTimeZone("US/Eastern"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 300); - - // Central time zone, UTC−06:00 - time_zone_extension->SetTimeZone("America/Chicago"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 360); - - // Mountain time zone, UTC−07:00 - time_zone_extension->SetTimeZone("US/Mountain"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 420); - - // Pacific time zone, UTC-08:00 - time_zone_extension->SetTimeZone("US/Pacific"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 480); - - // Alaska time zone, UTC-09:00 - time_zone_extension->SetTimeZone("US/Alaska"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 540); - - // Hawaii-Aleutian time zone, UTC-10:00 - time_zone_extension->SetTimeZone("Pacific/Honolulu"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 600); - - // American Samoa time zone, UTC-11:00 - time_zone_extension->SetTimeZone("US/Samoa"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, 660); - - // American Samoa time zone, UTC+10:00 - time_zone_extension->SetTimeZone("Pacific/Guam"); - zone = SbTimeZoneGetCurrent(); - EXPECT_EQ(zone, -600); - } +#if defined(_WIN32) + +std::array timeZonesWithExpectedTimeValues{ + TimeZoneWithExpectValue("UTC", 0, 0), + TimeZoneWithExpectValue("Atlantic Standard Time", 240, 180), + TimeZoneWithExpectValue("Eastern Standard Time", 300, 240), + TimeZoneWithExpectValue("Central Standard Time", 360, 300), + TimeZoneWithExpectValue("Mountain Standard Time", 420, 360), + TimeZoneWithExpectValue("Pacific Standard Time", 480, 420), + TimeZoneWithExpectValue("Yukon Standard Time", 420, 420), + TimeZoneWithExpectValue("Samoa Standard Time", -780, -780), + TimeZoneWithExpectValue("China Standard Time", -480, -480), + TimeZoneWithExpectValue("Central European Standard Time", -60, -120), + TimeZoneWithExpectValue("Omsk Standard Time", -360, -360), + TimeZoneWithExpectValue("Cen. Australia Standard Time", -570, -630)}; + +#else + +std::array timeZonesWithExpectedTimeValues{ + TimeZoneWithExpectValue("UTC", 0, 0), + TimeZoneWithExpectValue("America/Puerto_Rico", 240, 240), + TimeZoneWithExpectValue("America/New_York", 300, 300), + TimeZoneWithExpectValue("US/Eastern", 300, 300), + TimeZoneWithExpectValue("America/Chicago", 360, 360), + TimeZoneWithExpectValue("US/Mountain", 420, 420), + TimeZoneWithExpectValue("US/Pacific", 480, 480), + TimeZoneWithExpectValue("US/Alaska", 540, 540), + TimeZoneWithExpectValue("Pacific/Honolulu", 600, 600), + TimeZoneWithExpectValue("US/Samoa", 660, 660), + TimeZoneWithExpectValue("Pacific/Guam", -600, -600)}; + +#endif + +TEST_P(SbTimeZoneGetCurrentSetTimeZoneTest, IsKindOfSane) { + EXPECT_TRUE(time_zone_extension->SetTimeZone(GetParam().timeZoneName.c_str())); + auto zone = SbTimeZoneGetCurrent(); + EXPECT_THAT(zone, ::testing::AnyOf(GetParam().expectedStandardValue, + GetParam().expectedDaylightValue)); } +INSTANTIATE_TEST_SUITE_P(SbTimeZoneGetCurrentSetTimeZoneTest, + SbTimeZoneGetCurrentSetTimeZoneTest, + ::testing::ValuesIn(timeZonesWithExpectedTimeValues)); + } // namespace } // namespace nplb } // namespace starboard diff --git a/starboard/nplb/time_zone_get_name_test.cc b/starboard/nplb/time_zone_get_name_test.cc index 97c20c8c55b8..98604b9132ae 100644 --- a/starboard/nplb/time_zone_get_name_test.cc +++ b/starboard/nplb/time_zone_get_name_test.cc @@ -49,7 +49,11 @@ TEST(SbTimeZoneGetNameTest, IsKindOfSane) { // ":Pacific/Kiritimati" is the western-most timezone at UTC+14. } +#if defined(_WIN32) +TEST(SbTimeZoneGetNameTest, DISABLED_IsIANAFormat) { +#else TEST(SbTimeZoneGetNameTest, IsIANAFormat) { +#endif const char* name = SbTimeZoneGetName(); SB_LOG(INFO) << "time zone name: " << name; char cpy[100]; diff --git a/starboard/shared/win32/system_get_extensions.cc b/starboard/shared/win32/system_get_extensions.cc index 09a5726bb0ad..fb3813624328 100644 --- a/starboard/shared/win32/system_get_extensions.cc +++ b/starboard/shared/win32/system_get_extensions.cc @@ -17,8 +17,10 @@ #include "starboard/common/string.h" #include "starboard/extension/configuration.h" #include "starboard/extension/graphics.h" +#include "starboard/extension/time_zone.h" #include "starboard/shared/win32/configuration.h" #include "starboard/shared/win32/graphics.h" +#include "starboard/shared/win32/time_zone.h" const void* SbSystemGetExtension(const char* name) { if (strcmp(name, kCobaltExtensionGraphicsName) == 0) { @@ -27,5 +29,8 @@ const void* SbSystemGetExtension(const char* name) { if (strcmp(name, kCobaltExtensionConfigurationName) == 0) { return starboard::shared::win32::GetConfigurationApi(); } + if (strcmp(name, kStarboardExtensionTimeZoneName) == 0) { + return starboard::shared::win32::GetTimeZoneApi(); + } return NULL; } diff --git a/starboard/shared/win32/time_zone.cc b/starboard/shared/win32/time_zone.cc new file mode 100644 index 000000000000..a98ed8a54e78 --- /dev/null +++ b/starboard/shared/win32/time_zone.cc @@ -0,0 +1,75 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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 "starboard/extension/time_zone.h" +#include "starboard/time_zone.h" +#include "starboard/common/log.h" + +#include +#include + +namespace starboard { +namespace shared { +namespace win32 { + +namespace { + +bool SetTimeZone(const char* time_zone_name) { + std::string tzName(time_zone_name); + std::wstring windowsTzName(tzName.begin(), tzName.end()); + + DYNAMIC_TIME_ZONE_INFORMATION dtzi{0}; + TIME_ZONE_INFORMATION tzi{0}; + int index = 0; + bool found = false; + + while (EnumDynamicTimeZoneInformation(index, &dtzi) == ERROR_SUCCESS) { + if (windowsTzName == dtzi.TimeZoneKeyName || + windowsTzName == dtzi.StandardName || + windowsTzName == dtzi.DaylightName) { + found = true; + break; + } + index++; + } + if (!found) { + SB_LOG(ERROR) << "Time zone: " << tzName.c_str() << "not found."; + return false; + } + auto result = SetDynamicTimeZoneInformation(&dtzi); + if (result == 0) { + DWORD error = GetLastError(); + SB_LOG(ERROR) << "SetDynamicTimeZoneInformation failed for time zone: " + << tzName.c_str() << " return code: " << result + << " last error: " << error; + return false; + } + + return true; +} + +const StarboardExtensionTimeZoneApi kTimeZoneApi = { + kStarboardExtensionTimeZoneName, + 1, // API version that's implemented. + &SetTimeZone, +}; + +} // namespace +const void* GetTimeZoneApi() { + return &kTimeZoneApi; +} + +} // namespace win32 +} // namespace shared +} // namespace starboard diff --git a/starboard/shared/win32/time_zone.h b/starboard/shared/win32/time_zone.h new file mode 100644 index 000000000000..ec23c6159f7c --- /dev/null +++ b/starboard/shared/win32/time_zone.h @@ -0,0 +1,28 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// 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 STARBOARD_SHARED_WIN32_TIME_ZONE_H_ +#define STARBOARD_SHARED_WIN32_TIME_ZONE_H_ + +namespace starboard { +namespace shared { +namespace win32 { + +const void* GetTimeZoneApi(); + +} // namespace win32 +} // namespace shared +} // namespace starboard + +#endif // STARBOARD_SHARED_WIN32_TIME_ZONE_H_ diff --git a/starboard/win/win32/BUILD.gn b/starboard/win/win32/BUILD.gn index 746db846b634..65c3ed8f0cc2 100644 --- a/starboard/win/win32/BUILD.gn +++ b/starboard/win/win32/BUILD.gn @@ -59,6 +59,7 @@ static_library("starboard_platform") { "//starboard/shared/win32/system_get_used_cpu_memory.cc", "//starboard/shared/win32/system_raise_platform_error.cc", "//starboard/shared/win32/system_symbolize.cc", + "//starboard/shared/win32/time_zone.cc", "//starboard/shared/win32/time_zone_get_name.cc", "//starboard/shared/win32/window_create.cc", "//starboard/shared/win32/window_destroy.cc",