src: make process.env.TZ setter clear tz cache
Since the presence of the libc and V8 timezone caches seem to be a perennial source of confusion to users ("why doesn't it work?!"), let's try to support that pattern by intercepting assignments to the TZ environment variable and reset the caches as a side effect. Fixes: https://github.com/nodejs/node/issues/19974 PR-URL: https://github.com/nodejs/node/pull/20026 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Steven R Loomis <srloomis@us.ibm.com> Reviewed-By: Timothy Gu <timothygu99@gmail.com>
This commit is contained in:
parent
58fe440c0f
commit
eba348b6ae
@ -2,6 +2,8 @@
|
||||
#include "node_errors.h"
|
||||
#include "node_process.h"
|
||||
|
||||
#include <time.h> // tzset(), _tzset()
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
@ -64,6 +66,19 @@ Mutex env_var_mutex;
|
||||
std::shared_ptr<KVStore> system_environment = std::make_shared<RealEnvStore>();
|
||||
} // namespace per_process
|
||||
|
||||
template <typename T>
|
||||
void DateTimeConfigurationChangeNotification(Isolate* isolate, const T& key) {
|
||||
if (key.length() == 2 && key[0] == 'T' && key[1] == 'Z') {
|
||||
#ifdef __POSIX__
|
||||
tzset();
|
||||
#else
|
||||
_tzset();
|
||||
#endif
|
||||
auto constexpr time_zone_detection = Isolate::TimeZoneDetection::kRedetect;
|
||||
isolate->DateTimeConfigurationChangeNotification(time_zone_detection);
|
||||
}
|
||||
}
|
||||
|
||||
Local<String> RealEnvStore::Get(Isolate* isolate,
|
||||
Local<String> property) const {
|
||||
Mutex::ScopedLock lock(per_process::env_var_mutex);
|
||||
@ -115,6 +130,7 @@ void RealEnvStore::Set(Isolate* isolate,
|
||||
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
|
||||
}
|
||||
#endif
|
||||
DateTimeConfigurationChangeNotification(isolate, key);
|
||||
}
|
||||
|
||||
int32_t RealEnvStore::Query(Isolate* isolate, Local<String> property) const {
|
||||
@ -150,6 +166,7 @@ void RealEnvStore::Delete(Isolate* isolate, Local<String> property) {
|
||||
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
|
||||
SetEnvironmentVariableW(key_ptr, nullptr);
|
||||
#endif
|
||||
DateTimeConfigurationChangeNotification(isolate, key);
|
||||
}
|
||||
|
||||
Local<Array> RealEnvStore::Enumerate(Isolate* isolate) const {
|
||||
|
47
test/parallel/test-process-env-tz.js
Normal file
47
test/parallel/test-process-env-tz.js
Normal file
@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
if (!common.isMainThread)
|
||||
common.skip('process.env.TZ is not intercepted in Workers');
|
||||
|
||||
if (common.isWindows) // Using a different TZ format.
|
||||
common.skip('todo: test on Windows');
|
||||
|
||||
const date = new Date('2018-04-14T12:34:56.789Z');
|
||||
|
||||
process.env.TZ = 'Europe/Amsterdam';
|
||||
|
||||
if (date.toString().includes('(Europe)'))
|
||||
common.skip('not using bundled ICU'); // Shared library or --with-intl=none.
|
||||
|
||||
if ('Sat Apr 14 2018 12:34:56 GMT+0000 (GMT)' === date.toString())
|
||||
common.skip('missing tzdata'); // Alpine buildbots lack Europe/Amsterdam.
|
||||
|
||||
if (date.toString().includes('(Central European Time)') ||
|
||||
date.toString().includes('(CET)')) {
|
||||
// The AIX and SmartOS buildbots report 2018 CEST as CET
|
||||
// because apparently for them that's still the deep future.
|
||||
common.skip('tzdata too old');
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
date.toString().replace('Central European Summer Time', 'CEST'),
|
||||
'Sat Apr 14 2018 14:34:56 GMT+0200 (CEST)');
|
||||
|
||||
process.env.TZ = 'Europe/London';
|
||||
assert.strictEqual(
|
||||
date.toString().replace('British Summer Time', 'BST'),
|
||||
'Sat Apr 14 2018 13:34:56 GMT+0100 (BST)');
|
||||
|
||||
process.env.TZ = 'Etc/UTC';
|
||||
assert.strictEqual(
|
||||
date.toString().replace('Coordinated Universal Time', 'UTC'),
|
||||
'Sat Apr 14 2018 12:34:56 GMT+0000 (UTC)');
|
||||
|
||||
// Just check that deleting the environment variable doesn't crash the process.
|
||||
// We can't really check the result of date.toString() because we don't know
|
||||
// the default time zone.
|
||||
delete process.env.TZ;
|
||||
date.toString();
|
Loading…
x
Reference in New Issue
Block a user