aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-05-23 00:40:12 -0700
committerGravatar GitHub <noreply@github.com> 2023-05-23 00:40:12 -0700
commit5b38c55c3db018a94505f61cd785f0dd40f442ac (patch)
treeaf522e38ffa9b6c400c500c76de1fdca4ab931db /src/bun.js/bindings/JSEnvironmentVariableMap.cpp
parent83e7b9e198b25c7af7905c5dcabe1e325c5a38fb (diff)
downloadbun-5b38c55c3db018a94505f61cd785f0dd40f442ac.tar.gz
bun-5b38c55c3db018a94505f61cd785f0dd40f442ac.tar.zst
bun-5b38c55c3db018a94505f61cd785f0dd40f442ac.zip
Support setting a timezone with `process.env.TZ` and `Bun.env.TZ` (#3018)
* Support setting a timezone via `process.env.TZ` * Implement `setTimeZone` in `bun:jsc` module * [breaking] `bun:test` now defaults to `Etc/UTC` timezone --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js/bindings/JSEnvironmentVariableMap.cpp')
-rw-r--r--src/bun.js/bindings/JSEnvironmentVariableMap.cpp72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
index b90d9f44c..5c0357066 100644
--- a/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
+++ b/src/bun.js/bindings/JSEnvironmentVariableMap.cpp
@@ -50,6 +50,64 @@ JSC_DEFINE_CUSTOM_SETTER(jsSetterEnvironmentVariable, (JSGlobalObject * globalOb
return true;
}
+JSC_DEFINE_CUSTOM_GETTER(jsTimeZoneEnvironmentVariableGetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName propertyName))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* thisObject = jsDynamicCast<JSObject*>(JSValue::decode(thisValue));
+ if (UNLIKELY(!thisObject))
+ return JSValue::encode(jsUndefined());
+
+ auto* clientData = WebCore::clientData(vm);
+
+ ZigString name = toZigString(propertyName.publicName());
+ ZigString value = { nullptr, 0 };
+
+ if (auto hasExistingValue = thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().dataPrivateName())) {
+ return JSValue::encode(hasExistingValue);
+ }
+
+ if (!Bun__getEnvValue(globalObject, &name, &value) || value.len == 0) {
+ return JSValue::encode(jsUndefined());
+ }
+
+ JSValue out = jsString(vm, Zig::toStringCopy(value));
+ thisObject->putDirect(vm, clientData->builtinNames().dataPrivateName(), out, 0);
+
+ return JSValue::encode(out);
+}
+
+// In Node.js, the "TZ" environment variable is special.
+// Setting it automatically updates the timezone.
+// We also expose an explicit setTimeZone function in bun:jsc
+JSC_DEFINE_CUSTOM_SETTER(jsTimeZoneEnvironmentVariableSetter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, EncodedJSValue value, PropertyName propertyName))
+{
+ VM& vm = globalObject->vm();
+ JSC::JSObject* object = JSValue::decode(thisValue).getObject();
+ if (!object)
+ return false;
+
+ JSValue decodedValue = JSValue::decode(value);
+ if (decodedValue.isString()) {
+ auto timeZoneName = decodedValue.toWTFString(globalObject);
+ if (timeZoneName.length() < 32) {
+ if (WTF::setTimeZoneOverride(timeZoneName)) {
+ vm.dateCache.resetIfNecessarySlow();
+ }
+ }
+ }
+
+ auto* clientData = WebCore::clientData(vm);
+ auto* builtinNames = &clientData->builtinNames();
+ auto privateName = builtinNames->dataPrivateName();
+ object->putDirect(vm, privateName, JSValue::decode(value), 0);
+
+ // Recreate this because the property visibility needs to be set correctly
+ object->putDirectCustomAccessor(vm, propertyName, JSC::CustomGetterSetter::create(vm, jsTimeZoneEnvironmentVariableGetter, jsTimeZoneEnvironmentVariableSetter), JSC::PropertyAttribute::CustomAccessor | 0);
+ return true;
+}
+
JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject)
{
VM& vm = globalObject->vm();
@@ -65,11 +123,25 @@ JSValue createEnvironmentVariablesMap(Zig::GlobalObject* globalObject)
object = constructEmptyObject(globalObject, globalObject->objectPrototype());
}
+ static NeverDestroyed<String> TZ = MAKE_STATIC_STRING_IMPL("TZ");
+ bool hasTZ = false;
for (size_t i = 0; i < count; i++) {
auto name = Zig::toStringCopy(names[i]);
+ if (name == TZ) {
+ hasTZ = true;
+ continue;
+ }
object->putDirectCustomAccessor(vm, Identifier::fromString(vm, name), JSC::CustomGetterSetter::create(vm, jsGetterEnvironmentVariable, jsSetterEnvironmentVariable), JSC::PropertyAttribute::CustomAccessor | 0);
}
+ unsigned int TZAttrs = JSC::PropertyAttribute::CustomAccessor | 0;
+ if (!hasTZ) {
+ TZAttrs |= JSC::PropertyAttribute::DontEnum;
+ }
+ object->putDirectCustomAccessor(
+ vm,
+ Identifier::fromString(vm, TZ), JSC::CustomGetterSetter::create(vm, jsTimeZoneEnvironmentVariableGetter, jsTimeZoneEnvironmentVariableSetter), TZAttrs);
+
return object;
}
} \ No newline at end of file