Skip to content

Commit

Permalink
Make timezone override work on Win
Browse files Browse the repository at this point in the history
  • Loading branch information
Iurii Semikhatskii authored and yury-s committed Apr 1, 2020
1 parent 25a65e1 commit 68e0c2c
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 18 deletions.
27 changes: 9 additions & 18 deletions docshell/base/nsDocShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -3418,32 +3416,25 @@ 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<icu::TimeZone> 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;
#else
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;
}
Expand Down
5 changes: 5 additions & 0 deletions dom/base/nsJSUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(); }

Expand Down
1 change: 1 addition & 0 deletions dom/base/nsJSUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ class nsJSUtils {
JSContext* aCx, mozilla::dom::Element* aElement,
JS::MutableHandleVector<JSObject*> aScopeChain);

static bool SetTimeZoneOverride(const char* timezoneId);
static void ResetTimeZone();

static bool DumpEnabled();
Expand Down
2 changes: 2 additions & 0 deletions js/public/Date.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
27 changes: 27 additions & 0 deletions js/src/vm/DateTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ void js::DateTimeInfo::internalResetTimeZone(ResetTimeZoneMode mode) {
}
}

void js::DateTimeInfo::internalSetTimeZoneOverride(mozilla::UniquePtr<icu::TimeZone> timeZone) {
timeZoneOverride_ = std::move(timeZone);
internalResetTimeZone(ResetTimeZoneMode::ResetEvenIfOffsetUnchanged);
}

void js::DateTimeInfo::updateTimeZone() {
MOZ_ASSERT(timeZoneStatus_ != TimeZoneStatus::Valid);

Expand Down Expand Up @@ -528,10 +533,27 @@ void js::ResetTimeZoneInternal(ResetTimeZoneMode mode) {
js::DateTimeInfo::resetTimeZone(mode);
}

void js::SetTimeZoneOverrideInternal(mozilla::UniquePtr<icu::TimeZone> 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<icu::TimeZone> 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
Expand Down Expand Up @@ -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;

Expand Down
7 changes: 7 additions & 0 deletions js/src/vm/DateTime.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ enum class ResetTimeZoneMode : bool {
*/
extern void ResetTimeZoneInternal(ResetTimeZoneMode mode);

extern void SetTimeZoneOverrideInternal(mozilla::UniquePtr<icu::TimeZone> 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
Expand Down Expand Up @@ -206,6 +208,7 @@ class DateTimeInfo {
// and js::ResyncICUDefaultTimeZone().
friend void js::ResetTimeZoneInternal(ResetTimeZoneMode);
friend void js::ResyncICUDefaultTimeZone();
friend void js::SetTimeZoneOverrideInternal(mozilla::UniquePtr<icu::TimeZone>);

static void resetTimeZone(ResetTimeZoneMode mode) {
auto guard = instance->lock();
Expand Down Expand Up @@ -302,6 +305,8 @@ class DateTimeInfo {
JS::UniqueChars locale_;
JS::UniqueTwoByteChars standardName_;
JS::UniqueTwoByteChars daylightSavingsName_;

mozilla::UniquePtr<icu::TimeZone> 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
Expand All @@ -317,6 +322,8 @@ class DateTimeInfo {

void internalResetTimeZone(ResetTimeZoneMode mode);

void internalSetTimeZoneOverride(mozilla::UniquePtr<icu::TimeZone> timeZone);

void updateTimeZone();

void internalResyncICUDefaultTimeZone();
Expand Down

0 comments on commit 68e0c2c

Please sign in to comment.