diff options
-rw-r--r-- | packages/bun-types/bun.d.ts | 14 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 8 | ||||
-rw-r--r-- | test/bun.js/setTimeout.test.js | 8 |
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 { |