Skip to content

Commit

Permalink
lib: support setting process.env.TZ on windows
Browse files Browse the repository at this point in the history
Fixes: #4230
Signed-off-by: James M Snell <[email protected]>
  • Loading branch information
jasnell committed May 12, 2021
1 parent 184e0f7 commit e59351b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
8 changes: 8 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,14 @@ int InitializeNodeWithArgs(std::vector<std::string>* argv,
return 9;
}
per_process::metadata.versions.InitializeIntlVersions();

# ifndef __POSIX__
std::string tz;
if (credentials::SafeGetenv("TZ", &tz) && !tz.empty()) {
i18n::SetDefaultTimeZone(tz.c_str());
}
# endif

#endif

NativeModuleEnv::InitializeCodeCache();
Expand Down
23 changes: 19 additions & 4 deletions src/node_env_var.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "env-inl.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_i18n.h"
#include "node_process.h"

#include <time.h> // tzset(), _tzset()
Expand Down Expand Up @@ -69,15 +70,29 @@ std::shared_ptr<KVStore> system_environment = std::make_shared<RealEnvStore>();
} // namespace per_process

template <typename T>
void DateTimeConfigurationChangeNotification(Isolate* isolate, const T& key) {
void DateTimeConfigurationChangeNotification(Isolate* isolate, const T& key, const char* val = nullptr) {
if (key.length() == 2 && key[0] == 'T' && key[1] == 'Z') {
#ifdef __POSIX__
tzset();
isolate->DateTimeConfigurationChangeNotification(
Isolate::TimeZoneDetection::kRedetect);
#else
_tzset();

# if defined(NODE_HAVE_I18N_SUPPORT)
isolate->DateTimeConfigurationChangeNotification(
Isolate::TimeZoneDetection::kSkip);

// On windows, the TZ environment is not supported out of the box.
// By default, v8 will only be able to detect the system configured
// timezone. This supports using the TZ environment variable to set
// the default timezone instead.
if (val != nullptr) i18n::SetDefaultTimeZone(val);
# else
isolate->DateTimeConfigurationChangeNotification(
Isolate::TimeZoneDetection::kRedetect);
# endif
#endif
auto constexpr time_zone_detection = Isolate::TimeZoneDetection::kRedetect;
isolate->DateTimeConfigurationChangeNotification(time_zone_detection);
}
}

Expand Down Expand Up @@ -128,7 +143,7 @@ void RealEnvStore::Set(Isolate* isolate,
if (key.length() > 0 && key[0] == '=') return;
#endif
uv_os_setenv(*key, *val);
DateTimeConfigurationChangeNotification(isolate, key);
DateTimeConfigurationChangeNotification(isolate, key, *val);
}

int32_t RealEnvStore::Query(const char* key) const {
Expand Down
8 changes: 8 additions & 0 deletions src/node_i18n.cc
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,14 @@ bool InitializeICUDirectory(const std::string& path) {
return status == U_ZERO_ERROR;
}

void SetDefaultTimeZone(const char* tzid) {
UChar lbl[255];
UErrorCode status = U_ZERO_ERROR;
u_charsToUChars(tzid, lbl, strlen(tzid) + 1);
ucal_setDefaultTimeZone(lbl, &status);
CHECK(U_SUCCESS(status));
}

int32_t ToUnicode(MaybeStackBuffer<char>* buf,
const char* input,
size_t length) {
Expand Down
2 changes: 2 additions & 0 deletions src/node_i18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ namespace i18n {

bool InitializeICUDirectory(const std::string& path);

void SetDefaultTimeZone(const char* tzid);

enum idna_mode {
// Default mode for maximum compatibility.
IDNA_DEFAULT,
Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-datetime-change-notify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

require('../common');
const assert = require('assert');

process.env.TZ = 'Etc/UTC';
assert.match(new Date().toString(), /GMT\+0000/);

process.env.TZ = 'America/New_York';
assert.match(new Date().toString(), /Eastern (Standard|Daylight) Time/);

process.env.TZ = 'America/Los_Angeles';
assert.match(new Date().toString(), /Pacific (Standard|Daylight) Time/);

0 comments on commit e59351b

Please sign in to comment.