diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 4be480a4ec0e3..a013080177ee2 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -17,8 +17,6 @@ #if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU # include "unicode/locid.h" -# include "unicode/timezone.h" -# include "unicode/unistr.h" #endif /* JS_HAS_INTL_API && !MOZ_SYSTEM_ICU */ #include "js/LocaleSensitive.h" @@ -3418,19 +3416,13 @@ nsDocShell::SetLanguageOverride(const nsAString& aLanguageOverride) { } NS_IMETHODIMP -nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride, bool* aSuccess) { +nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride, + bool* aSuccess) { NS_ENSURE_ARG(aSuccess); + NS_LossyConvertUTF16toASCII timeZoneId(aTimezoneOverride); + *aSuccess = nsJSUtils::SetTimeZoneOverride(timeZoneId.get()); - // Validate timezone id. - UniquePtr timezone(icu::TimeZone::createTimeZone( - icu::UnicodeString(NS_LossyConvertUTF16toASCII(aTimezoneOverride).get(), -1, US_INV))); - if (!timezone || *timezone == icu::TimeZone::getUnknown()) { - fprintf(stderr, "Invalid timezone id: %s\n", NS_LossyConvertUTF16toASCII(aTimezoneOverride).get()); - *aSuccess = false; - return NS_OK; - } - - // The env variable is read by js::DateTimeInfo::internalResyncICUDefaultTimeZone() + // Set TZ which affects localtime_s(). auto setTimeZoneEnv = [](const char* value) { #if defined(_WIN32) return _putenv_s("TZ", value) == 0; @@ -3438,12 +3430,11 @@ nsDocShell::OverrideTimezone(const nsAString& aTimezoneOverride, bool* aSuccess) return setenv("TZ", value, true) == 0; #endif /* _WIN32 */ }; - - *aSuccess = setTimeZoneEnv(NS_LossyConvertUTF16toASCII(aTimezoneOverride).get()); if (*aSuccess) { - nsJSUtils::ResetTimeZone(); - } else { - fprintf(stderr, "Failed to change timezone to '%s'\n", NS_LossyConvertUTF16toASCII(aTimezoneOverride).get()); + *aSuccess = setTimeZoneEnv(timeZoneId.get()); + if (!*aSuccess) { + fprintf(stderr, "Failed to set 'TZ' to '%s'\n", timeZoneId.get()); + } } return NS_OK; } diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index ac68cf67ecc61..3b9fd67742db5 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -617,6 +617,11 @@ bool nsJSUtils::GetScopeChainForElement( return true; } +/* static */ +bool nsJSUtils::SetTimeZoneOverride(const char* timezoneId) { + return JS::SetTimeZoneOverride(timezoneId); +} + /* static */ void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index 2b654b490e53d..462e60d7fa84f 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -241,6 +241,7 @@ class nsJSUtils { JSContext* aCx, mozilla::dom::Element* aElement, JS::MutableHandleVector aScopeChain); + static bool SetTimeZoneOverride(const char* timezoneId); static void ResetTimeZone(); static bool DumpEnabled(); diff --git a/js/public/Date.h b/js/public/Date.h index 8a2dddc9a2ab5..d5bf241dec39f 100644 --- a/js/public/Date.h +++ b/js/public/Date.h @@ -56,6 +56,8 @@ namespace JS { */ extern JS_PUBLIC_API void ResetTimeZone(); +extern JS_PUBLIC_API bool SetTimeZoneOverride(const char* timezoneId); + class ClippedTime; inline ClippedTime TimeClip(double time); diff --git a/js/src/vm/DateTime.cpp b/js/src/vm/DateTime.cpp index d27ba46016e0a..3cfa6ec992723 100644 --- a/js/src/vm/DateTime.cpp +++ b/js/src/vm/DateTime.cpp @@ -168,6 +168,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) { } } +void js::DateTimeInfo::internalSetTimeZoneOverride(mozilla::UniquePtr timeZone) { + timeZoneOverride_ = std::move(timeZone); + internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); +} + void js::DateTimeInfo::updateTimeZone() { MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid); @@ -528,10 +533,27 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) { js::DateTimeInfo::resetTimeZone(mode); } +void js::SetTimeZoneOverrideInternal(mozilla::UniquePtr timeZone) { + auto guard = js::DateTimeInfo::instance->lock(); + guard->internalSetTimeZoneOverride(std::move(timeZone)); +} + JS_PUBLIC_API void JS::ResetTimeZone() { js::ResetTimeZoneInternal(js::ResetTimeZoneMode::ResetEvenIfOffsetUnchanged); } +JS_PUBLIC_API bool JS::SetTimeZoneOverride(const char* timeZoneId) { + // Validate timezone id. + mozilla::UniquePtr timeZone(icu::TimeZone::createTimeZone( + icu::UnicodeString(timeZoneId, -1, US_INV))); + if (!timeZone || *timeZone == icu::TimeZone::getUnknown()) { + fprintf(stderr, "Invalid timezone id: %s\n", timeZoneId); + return false; + } + js::SetTimeZoneOverrideInternal(std::move(timeZone)); + return true; +} + #if defined(XP_WIN) static bool IsOlsonCompatibleWindowsTimeZoneId(const char* tz) { // ICU ignores the TZ environment variable on Windows and instead directly @@ -726,6 +748,11 @@ void js::ResyncICUDefaultTimeZone() { void js::DateTimeInfo::internalResyncICUDefaultTimeZone() { #if JS_HAS_INTL_API && !MOZ_SYSTEM_ICU + if (timeZoneOverride_) { + icu::TimeZone::setDefault(*timeZoneOverride_); + return; + } + if (const char* tz = std::getenv("TZ")) { icu::UnicodeString tzid; diff --git a/js/src/vm/DateTime.h b/js/src/vm/DateTime.h index 25c5b01fc54c8..490c5ce49cd9b 100644 --- a/js/src/vm/DateTime.h +++ b/js/src/vm/DateTime.h @@ -67,6 +67,8 @@ enum class ResetTimeZoneMode : bool { */ extern void ResetTimeZoneInternal(ResetTimeZoneMode mode); +extern void SetTimeZoneOverrideInternal(mozilla::UniquePtr timeZone); + /** * ICU's default time zone, used for various date/time formatting operations * that include the local time in the representation, is allowed to go stale @@ -206,6 +208,7 @@ class DateTimeInfo { // and js::ResyncICUDefaultTimeZone(). friend void js::ResetTimeZoneInternal(ResetTimeZoneMode); friend void js::ResyncICUDefaultTimeZone(); + friend void js::SetTimeZoneOverrideInternal(mozilla::UniquePtr); static void resetTimeZone(ResetTimeZoneMode mode) { auto guard = instance->lock(); @@ -302,6 +305,8 @@ class DateTimeInfo { JS::UniqueChars locale_; JS::UniqueTwoByteChars standardName_; JS::UniqueTwoByteChars daylightSavingsName_; + + mozilla::UniquePtr timeZoneOverride_; #else // Restrict the data-time range to the minimum required time_t range as // specified in POSIX. Most operating systems support 64-bit time_t @@ -317,6 +322,8 @@ class DateTimeInfo { void internalResetTimeZone(ResetTimeZoneMode mode); + void internalSetTimeZoneOverride(mozilla::UniquePtr timeZone); + void updateTimeZone(); void internalResyncICUDefaultTimeZone();