Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
strategy:
matrix:
node-version:
- "12"
- "14"
- "20"
- "22"
- "24"
- "26"
name: tests
"on":
- push
18 changes: 18 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ declare namespace PostgresInterval {
* ```
*/
toISOStringShort(): string;
/**
* Returns a [`Temporal.Duration`](https://tc39.es/proposal-temporal/docs/duration.html) representing the interval.
*
* Requires `globalThis.Temporal` (Node 26+, or a polyfill assigned to the global). Throws otherwise.
*
* Postgres mixed-sign intervals (e.g. `1 mon -1 days`) throw a `RangeError`, because `Temporal.Duration` requires a single sign across all fields.
*
* The `Temporal` types are not yet in the default TypeScript lib. For this signature to resolve, your project needs Temporal lib types (the TypeScript lib once available, or `@js-temporal/polyfill` types).
*
* ```js
* var parse = require('postgres-interval')
* var interval = parse('01:02:03')
* // => { hours: 1, minutes: 2, seconds: 3 }
* interval.toTemporalDuration().toString()
* // PT1H2M3S
* ```
*/
toTemporalDuration(): Temporal.Duration;
}
}

Expand Down
19 changes: 19 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,25 @@ PostgresInterval.prototype.toISOStringShort = function () {
return toISOString.call(this, { short: true })
}

PostgresInterval.prototype.toTemporalDuration = function () {
if (typeof globalThis.Temporal === 'undefined') {
throw new Error('Temporal is not available. It ships unflagged in Node 26+. On older runtimes, install a polyfill (e.g. @js-temporal/polyfill) and assign it to globalThis.Temporal.')
}

const totalMicroseconds = Math.round(this.milliseconds * 1000)

return globalThis.Temporal.Duration.from({
years: this.years,
months: this.months,
days: this.days,
hours: this.hours,
minutes: this.minutes,
seconds: this.seconds,
milliseconds: Math.trunc(totalMicroseconds / 1000),
microseconds: totalMicroseconds % 1000
})
}

function toISOString ({ short }) {
let datePart = ''

Expand Down
10 changes: 10 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ Also available as `interval.toISO()` for backwards compatibility.

Returns an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) compliant string shortened to minimum length, for example `PT9M`.

#### `interval.toTemporalDuration()` -> `Temporal.Duration`

Returns a [`Temporal.Duration`](https://tc39.es/proposal-temporal/docs/duration.html) representing the interval.

Requires `globalThis.Temporal`. It ships unflagged in Node 26+. On older runtimes, install a polyfill such as [`@js-temporal/polyfill`](https://www.npmjs.com/package/@js-temporal/polyfill) and assign it to `globalThis.Temporal`. The method throws if `Temporal` is unavailable.

Postgres mixed-sign intervals (e.g. `1 mon -1 days`) throw a `RangeError`. `Temporal.Duration` requires all fields to share a single sign, which these intervals violate.

The `Temporal` types are not yet in the default TypeScript lib. To resolve the return type, your project needs Temporal lib types: the TypeScript lib once available, or the `@js-temporal/polyfill` types. This package adds no type dependency.

## License

MIT © [Ben Drucker](http://bendrucker.me)
35 changes: 35 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,40 @@ test(function (t) {
t.end()
})

if (typeof globalThis.Temporal !== 'undefined') {
t.test('toTemporalDuration', function (t) {
const simple = interval('01:02:03').toTemporalDuration()
t.equal(simple.hours, 1)
t.equal(simple.minutes, 2)
t.equal(simple.seconds, 3)

const full = interval('1 year 2 mons 3 days 04:05:06').toTemporalDuration()
t.equal(full.years, 1)
t.equal(full.months, 2)
t.equal(full.days, 3)
t.equal(full.hours, 4)
t.equal(full.minutes, 5)
t.equal(full.seconds, 6)

const subSecond = interval('00:00:00.123456').toTemporalDuration()
t.equal(subSecond.milliseconds, 123)
t.equal(subSecond.microseconds, 456)

t.throws(function () {
interval('1 mon -1 days').toTemporalDuration()
}, RangeError, 'mixed-sign interval throws')

const negative = interval('-01:02:03').toTemporalDuration()
t.equal(negative.sign, -1)
t.equal(negative.hours, -1)
t.equal(negative.minutes, -2)
t.equal(negative.seconds, -3)

t.end()
})
} else {
t.skip('toTemporalDuration (Temporal unavailable)')
}

t.end()
})
Loading