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.

PR-URL: https://github.com/nodejs/node/pull/20026
Fixes: https://github.com/nodejs/node/issues/19974
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Ben Noordhuis 2018-04-14 11:28:19 +02:00 committed by Ruben Bridgewater
parent 5af28c26cf
commit 1d1ab76e17
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
2 changed files with 33 additions and 0 deletions

View File

@ -80,6 +80,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> // tzset(), _tzset()
#include <string>
#include <vector>
@ -135,6 +136,7 @@ using v8::Array;
using v8::ArrayBuffer;
using v8::Boolean;
using v8::Context;
using v8::Date;
using v8::EscapableHandleScope;
using v8::Exception;
using v8::Float64Array;
@ -2679,6 +2681,10 @@ static void EnvSetter(Local<Name> property,
node::Utf8Value key(info.GetIsolate(), property);
node::Utf8Value val(info.GetIsolate(), value);
setenv(*key, *val, 1);
if (key.length() == 2 && key[0] == 'T' && key[1] == 'Z') {
tzset();
Date::DateTimeConfigurationChangeNotification(info.GetIsolate());
}
#else // _WIN32
node::TwoByteValue key(info.GetIsolate(), property);
node::TwoByteValue val(info.GetIsolate(), value);
@ -2687,6 +2693,10 @@ static void EnvSetter(Local<Name> property,
if (key_ptr[0] != L'=') {
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
}
if (key.length() == 2 && key[0] == L'T' && key[1] == L'Z') {
_tzset();
Date::DateTimeConfigurationChangeNotification(info.GetIsolate());
}
#endif
// Whether it worked or not, always return value.
info.GetReturnValue().Set(value);

View File

@ -0,0 +1,23 @@
'use strict';
const common = require('../common');
const assert = require('assert');
if (common.isWindows) // Using a different TZ format.
common.skip('todo: test on Windows');
if (common.isAIX || common.isSunOS) // Reports 2018 CEST as CET.
common.skip('tzdata too old');
const date = new Date('2018-04-14T12:34:56.789Z');
process.env.TZ = 'Europe/Amsterdam';
if (/\(Europe\)/.test(date.toString()))
common.skip('not using bundled ICU'); // Shared library or --with-intl=none.
assert.strictEqual(date.toString(), 'Sat Apr 14 2018 14:34:56 GMT+0200 (CEST)');
process.env.TZ = 'Europe/London';
assert.strictEqual(date.toString(), 'Sat Apr 14 2018 13:34:56 GMT+0100 (BST)');
process.env.TZ = 'Etc/UTC';
assert.strictEqual(date.toString(), 'Sat Apr 14 2018 12:34:56 GMT+0000 (UTC)');