diff --git a/starboard/linux/shared/BUILD.gn b/starboard/linux/shared/BUILD.gn index 237e75fb1b407..536bfe5545090 100644 --- a/starboard/linux/shared/BUILD.gn +++ b/starboard/linux/shared/BUILD.gn @@ -135,6 +135,7 @@ static_library("starboard_platform_sources") { "//starboard/shared/linux/thread_get_id.cc", "//starboard/shared/linux/thread_get_name.cc", "//starboard/shared/linux/thread_set_name.cc", + "//starboard/shared/linux/time_zone_get_name.cc", "//starboard/shared/nouser/user_get_current.cc", "//starboard/shared/nouser/user_get_property.cc", "//starboard/shared/nouser/user_get_signed_in.cc", @@ -219,7 +220,6 @@ static_library("starboard_platform_sources") { "//starboard/shared/posix/time_get_now.cc", "//starboard/shared/posix/time_is_time_thread_now_supported.cc", "//starboard/shared/posix/time_zone_get_current.cc", - "//starboard/shared/posix/time_zone_get_name.cc", "//starboard/shared/pthread/condition_variable_broadcast.cc", "//starboard/shared/pthread/condition_variable_create.cc", "//starboard/shared/pthread/condition_variable_destroy.cc", diff --git a/starboard/nplb/time_zone_get_name_test.cc b/starboard/nplb/time_zone_get_name_test.cc index a3e013caff6d9..318cbfc60b616 100644 --- a/starboard/nplb/time_zone_get_name_test.cc +++ b/starboard/nplb/time_zone_get_name_test.cc @@ -12,10 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + +#include "starboard/common/log.h" +#include "starboard/extension/time_zone.h" #include "starboard/nplb/time_constants.h" +#include "starboard/system.h" #include "starboard/time_zone.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::AnyOf; +using testing::MatchesRegex; + namespace starboard { namespace nplb { namespace { @@ -41,6 +50,27 @@ TEST(SbTimeZoneGetNameTest, IsKindOfSane) { // ":Pacific/Kiritimati" is the western-most timezone at UTC+14. } +TEST(SbTimeZoneGetNameTest, IsIANAFormat) { + const char* name = SbTimeZoneGetName(); + SB_LOG(INFO) << "time zone name: " << name; + char cpy[100]; + snprintf(cpy, sizeof(cpy), "%s", name); + char* continent = strtok(cpy, "/"); + // The time zone ID starts with a Continent or Ocean name. + EXPECT_THAT( + continent, + testing::AnyOf(std::string("Asia"), std::string("America"), + std::string("Africa"), std::string("Europe"), + std::string("Australia"), std::string("Pacific"), + std::string("Atlantic"), std::string("Antarctica"), + // time zone can be "Etc/UTC" if unset(such as on + // CI builders), shouldn't happen in production. + // TODO(b/304351956): Remove Etc after fixing builders. + std::string("Indian"), std::string("Etc"))); + char* city = strtok(NULL, "/"); + EXPECT_TRUE(strlen(city) != 0); +} + } // namespace } // namespace nplb } // namespace starboard diff --git a/starboard/raspi/shared/BUILD.gn b/starboard/raspi/shared/BUILD.gn index 8d797b300db7a..39ca20e177c6c 100644 --- a/starboard/raspi/shared/BUILD.gn +++ b/starboard/raspi/shared/BUILD.gn @@ -113,6 +113,7 @@ static_library("starboard_platform_sources") { "//starboard/shared/linux/thread_get_id.cc", "//starboard/shared/linux/thread_get_name.cc", "//starboard/shared/linux/thread_set_name.cc", + "//starboard/shared/linux/time_zone_get_name.cc", "//starboard/shared/nouser/user_get_current.cc", "//starboard/shared/nouser/user_get_property.cc", "//starboard/shared/nouser/user_get_signed_in.cc", @@ -189,7 +190,6 @@ static_library("starboard_platform_sources") { "//starboard/shared/posix/time_get_now.cc", "//starboard/shared/posix/time_is_time_thread_now_supported.cc", "//starboard/shared/posix/time_zone_get_current.cc", - "//starboard/shared/posix/time_zone_get_name.cc", "//starboard/shared/pthread/condition_variable_broadcast.cc", "//starboard/shared/pthread/condition_variable_create.cc", "//starboard/shared/pthread/condition_variable_destroy.cc", diff --git a/starboard/shared/linux/time_zone_get_name.cc b/starboard/shared/linux/time_zone_get_name.cc new file mode 100644 index 0000000000000..4b1819edb82f3 --- /dev/null +++ b/starboard/shared/linux/time_zone_get_name.cc @@ -0,0 +1,75 @@ +// Copyright 2015 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 +#include +#include + +#include "starboard/common/log.h" +#include "starboard/time_zone.h" + +#define TZDEFAULT "/etc/localtime" +#define TZZONEINFOTAIL "/zoneinfo/" +#define isNonDigit(ch) (ch < '0' || '9' < ch) + +static char gTimeZoneBuffer[PATH_MAX]; +static char* gTimeZoneBufferPtr = NULL; + +static bool isValidOlsonID(const char* id) { + int32_t idx = 0; + + /* Determine if this is something like Iceland (Olson ID) + or AST4ADT (non-Olson ID) */ + while (id[idx] && isNonDigit(id[idx]) && id[idx] != ',') { + idx++; + } + + /* If we went through the whole string, then it might be okay. + The timezone is sometimes set to "CST-7CDT", "CST6CDT5,J129,J131/19:30", + "GRNLNDST3GRNLNDDT" or similar, so we cannot use it. + The rest of the time it could be an Olson ID. George */ + return static_cast(id[idx] == 0 || strcmp(id, "PST8PDT") == 0 || + strcmp(id, "MST7MDT") == 0 || + strcmp(id, "CST6CDT") == 0 || + strcmp(id, "EST5EDT") == 0); +} + +// Similar to how ICU::putil.cpp gets IANA(Olsen) timezone ID. +const char* SbTimeZoneGetName() { + /* + This is a trick to look at the name of the link to get the Olson ID + because the tzfile contents is underspecified. + This isn't guaranteed to work because it may not be a symlink. + But this is production-tested solution for most versions of Linux. + */ + + if (gTimeZoneBufferPtr == NULL) { + int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, + sizeof(gTimeZoneBuffer) - 1); + if (0 < ret) { + int32_t tzZoneInfoTailLen = strlen(TZZONEINFOTAIL); + gTimeZoneBuffer[ret] = 0; + char* tzZoneInfoTailPtr = strstr(gTimeZoneBuffer, TZZONEINFOTAIL); + + if (tzZoneInfoTailPtr != NULL && + isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen)) { + return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen); + } + } + SB_NOTREACHED(); + return ""; + } else { + return gTimeZoneBufferPtr; + } +} diff --git a/starboard/shared/posix/time_zone_get_name.cc b/starboard/shared/posix/time_zone_get_name.cc deleted file mode 100644 index 5a1e013c44816..0000000000000 --- a/starboard/shared/posix/time_zone_get_name.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 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/time_zone.h" - -#include - -const char* SbTimeZoneGetName() { - // TODO: Using tzname assumes that tzset() has been called at some - // point. That should happen as part of Starboard's main loop initialization, - // but that doesn't exist yet. - return tzname[0]; -} diff --git a/starboard/time_zone.h b/starboard/time_zone.h index a8ac53bc1cf46..d140338b58fd4 100644 --- a/starboard/time_zone.h +++ b/starboard/time_zone.h @@ -29,7 +29,7 @@ extern "C" { // The number of minutes west of the Greenwich Prime Meridian, NOT including // Daylight Savings Time adjustments. // -// For example: PST/PDT is 480 minutes (28800 seconds, 8 hours). +// For example: America/Los_Angeles is 480 minutes (28800 seconds, 8 hours). typedef int SbTimeZone; // Gets the system's current SbTimeZone in minutes. diff --git a/starboard/win/win32/test_filters.py b/starboard/win/win32/test_filters.py index cf8621fb81b02..9ab3ffd84f04f 100644 --- a/starboard/win/win32/test_filters.py +++ b/starboard/win/win32/test_filters.py @@ -53,6 +53,10 @@ # Enable once verified on the platform. 'SbMediaCanPlayMimeAndKeySystem.MinimumSupport', + + # Windows uses a special time zone format that ICU accepts, so we don't enforce IANA. + # TODO(b/304335954): Re-enable the test after fixing Windows implementation. + 'SbTimeZoneGetNameTest.IsIANAFormat', ], 'player_filter_tests': [ # These tests fail on our VMs for win-win32 builds due to missing