From 1d1ab76e1737da4229b3a0774c60a8fbead89040 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 14 Apr 2018 11:28:19 +0200 Subject: [PATCH] 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 Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/node.cc | 10 ++++++++++ test/parallel/test-process-env-tz.js | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 test/parallel/test-process-env-tz.js diff --git a/src/node.cc b/src/node.cc index 90defba40ba95e..355b71de672ae3 100644 --- a/src/node.cc +++ b/src/node.cc @@ -80,6 +80,7 @@ #include #include #include +#include // tzset(), _tzset() #include #include @@ -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 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 property, if (key_ptr[0] != L'=') { SetEnvironmentVariableW(key_ptr, reinterpret_cast(*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); diff --git a/test/parallel/test-process-env-tz.js b/test/parallel/test-process-env-tz.js new file mode 100644 index 00000000000000..7e077588d46e64 --- /dev/null +++ b/test/parallel/test-process-env-tz.js @@ -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)');