From c70ade08ed98ef9af8ea6232510188f165abfadb Mon Sep 17 00:00:00 2001 From: Sebastian Lorenz Date: Mon, 27 Jan 2025 10:38:28 +0100 Subject: [PATCH] fix handling of hrtime in `Duration.decode` --- .changeset/good-pillows-leave.md | 5 +++++ packages/effect/src/Duration.ts | 14 ++++++++++---- packages/effect/test/Duration.test.ts | 4 ++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 .changeset/good-pillows-leave.md diff --git a/.changeset/good-pillows-leave.md b/.changeset/good-pillows-leave.md new file mode 100644 index 00000000000..20c2ae43a91 --- /dev/null +++ b/.changeset/good-pillows-leave.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Fixed handling of hrtime in `Duration.decode` diff --git a/packages/effect/src/Duration.ts b/packages/effect/src/Duration.ts index a92dd7b0ed9..9e2d55d1bf8 100644 --- a/packages/effect/src/Duration.ts +++ b/packages/effect/src/Duration.ts @@ -83,7 +83,7 @@ export type DurationInput = | Duration | number // millis | bigint // nanos - | [seconds: number, nanos: number] + | readonly [seconds: number, nanos: number] | `${number} ${Unit}` const DURATION_REGEX = /^(-?\d+(?:\.\d+)?)\s+(nanos?|micros?|millis?|seconds?|minutes?|hours?|days?|weeks?)$/ @@ -98,10 +98,16 @@ export const decode = (input: DurationInput): Duration => { return millis(input) } else if (isBigInt(input)) { return nanos(input) - } else if (Array.isArray(input)) { - if (input.length === 2 && isNumber(input[0]) && isNumber(input[1])) { - return nanos(BigInt(input[0]) * bigint1e9 + BigInt(input[1])) + } else if (Array.isArray(input) && input.length === 2 && input.every(isNumber)) { + if (input[0] === -Infinity || input[1] === -Infinity || Number.isNaN(input[0]) || Number.isNaN(input[1])) { + return zero } + + if (input[0] === Infinity || input[1] === Infinity) { + return infinity + } + + return nanos(BigInt(Math.round(input[0]) * 1_000_000_000) + BigInt(Math.round(input[1]))) } else if (isString(input)) { DURATION_REGEX.lastIndex = 0 // Reset the lastIndex before each use const match = DURATION_REGEX.exec(input) diff --git a/packages/effect/test/Duration.test.ts b/packages/effect/test/Duration.test.ts index 118bb3ff30b..78da845c064 100644 --- a/packages/effect/test/Duration.test.ts +++ b/packages/effect/test/Duration.test.ts @@ -36,6 +36,8 @@ describe("Duration", () => { expect(Duration.decode([500, 123456789])).toEqual(Duration.nanos(500123456789n)) expect(Duration.decode([-500, 123456789])).toEqual(Duration.zero) + expect(Duration.decode([Infinity, 0])).toEqual(Duration.infinity) + expect(Duration.decode([-Infinity, 0])).toEqual(Duration.zero) expect(() => Duration.decode("1.5 secs" as any)).toThrowError(new Error("Invalid DurationInput")) expect(() => Duration.decode(true as any)).toThrowError(new Error("Invalid DurationInput")) @@ -72,6 +74,8 @@ describe("Duration", () => { expect(Duration.decodeUnknown([500, 123456789])).toEqual(Option.some(Duration.nanos(500123456789n))) expect(Duration.decodeUnknown([-500, 123456789])).toEqual(Option.some(Duration.zero)) + expect(Duration.decodeUnknown([Infinity, 0])).toEqual(Option.some(Duration.infinity)) + expect(Duration.decodeUnknown([-Infinity, 0])).toEqual(Option.some(Duration.zero)) expect(Duration.decodeUnknown("1.5 secs")).toEqual(Option.none()) expect(Duration.decodeUnknown(true)).toEqual(Option.none())