aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/bun-types/bun.d.ts14
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp8
-rw-r--r--test/bun.js/setTimeout.test.js8
3 files changed, 27 insertions, 3 deletions
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index 03f5c407c..ba626c00d 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -2155,7 +2155,9 @@ declare module "bun" {
* Resolve a `Promise` after milliseconds. This is like
* {@link setTimeout} except it returns a `Promise`.
*
- * @param ms milliseconds to delay resolving the promise. This is a minimum number. It may take longer.
+ * @param ms milliseconds to delay resolving the promise. This is a minimum
+ * number. It may take longer. If a {@link Date} is passed, it will sleep until the
+ * {@link Date} is reached.
*
* @example
* ## Sleep for 1 second
@@ -2168,14 +2170,20 @@ declare module "bun" {
* ```ts
* await Bun.sleep(10);
* ```
+ * ## Sleep until `Date`
+ *
+ * ```ts
+ * const target = new Date();
+ * target.setSeconds(target.getSeconds() + 1);
+ * await Bun.sleep(target);
+ * ```
* Internally, `Bun.sleep` is the equivalent of
* ```ts
* await new Promise((resolve) => setTimeout(resolve, ms));
* ```
- *
* As always, you can use `Bun.sleep` or the imported `sleep` function interchangeably.
*/
- export function sleep(ms: number): Promise<void>;
+ export function sleep(ms: number | Date): Promise<void>;
/**
* Sleep the thread for a given number of milliseconds
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 5eeaf9804..54ccba343 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -108,6 +108,7 @@
#include "ModuleLoader.h"
#include "ZigGeneratedClasses.h"
+#include "JavaScriptCore/DateInstance.h"
#include "BunPlugin.h"
@@ -810,6 +811,13 @@ JSC_DEFINE_HOST_FUNCTION(functionBunSleep,
JSC::VM& vm = globalObject->vm();
JSC::JSValue millisecondsValue = callFrame->argument(0);
+
+ if (millisecondsValue.inherits<JSC::DateInstance>()) {
+ auto now = MonotonicTime::now();
+ auto milliseconds = jsCast<JSC::DateInstance*>(millisecondsValue)->internalNumber() - now.approximateWallTime().secondsSinceEpoch().milliseconds();
+ millisecondsValue = JSC::jsNumber(milliseconds > 0 ? milliseconds : 0);
+ }
+
if (!millisecondsValue.isNumber()) {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "sleep expects a number (milliseconds)"_s);
diff --git a/test/bun.js/setTimeout.test.js b/test/bun.js/setTimeout.test.js
index 52430bd03..393a32bbe 100644
--- a/test/bun.js/setTimeout.test.js
+++ b/test/bun.js/setTimeout.test.js
@@ -116,6 +116,14 @@ it("Bun.sleep propagates exceptions", async () => {
}
});
+it("Bun.sleep works with a Date object", async () => {
+ var ten_ms = new Date();
+ ten_ms.setMilliseconds(ten_ms.getMilliseconds() + 10);
+ const now = performance.now();
+ await Bun.sleep(ten_ms);
+ expect(performance.now() - now).toBeGreaterThanOrEqual(10);
+});
+
it("node.js timers/promises setTimeout propagates exceptions", async () => {
const { setTimeout } = require("timers/promises");
try {