npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

temporal_rs

v0.1.9

Published

Native Node.js and WASM bindings for [temporal_rs](https://github.com/boa-dev/temporal) — the Rust implementation of the [TC39 Temporal proposal](https://tc39.es/proposal-temporal/).

Readme

temporal_rs

Native Node.js and WASM bindings for temporal_rs — the Rust implementation of the TC39 Temporal proposal.

CI npm

Install

npm install temporal_rs

Prebuilt native binaries are available for:

| Platform | Architecture | |-----------------|-------------| | macOS | arm64, x64 | | Linux (glibc) | x64, arm64 | | Linux (musl) | x64 | | Windows (MSVC) | x64, arm64 |

Quick Start

import { Temporal } from 'temporal_rs'

// Current time
const now = Temporal.Now.instant()
const today = Temporal.Now.plainDateISO()
const zonedNow = Temporal.Now.zonedDateTimeISO()

// Dates
const date = new Temporal.PlainDate(2024, 3, 15)
const parsed = Temporal.PlainDate.from('2024-03-15')
console.log(date.dayOfWeek)  // 5 (Friday)
console.log(date.inLeapYear) // true

// Times
const time = new Temporal.PlainTime(13, 30, 45)
const morning = Temporal.PlainTime.from('09:00:00')

// Date + Time
const dt = new Temporal.PlainDateTime(2024, 12, 31, 23, 59)

// Zoned (timezone-aware)
const zdt = Temporal.ZonedDateTime.from('2024-03-15T12:00:00-04:00[America/New_York]')
console.log(zdt.offset)      // '-04:00'
console.log(zdt.hoursInDay)  // 24

// Instants (exact time)
const inst = Temporal.Instant.fromEpochMilliseconds(Date.now())

// Durations
const dur = Temporal.Duration.from('P1Y2M3DT4H5M6S')
console.log(dur.years)   // 1
console.log(dur.months)  // 2

Arithmetic

const { PlainDate, Duration } = Temporal

const date = PlainDate.from('2024-01-31')
const oneMonth = Duration.from('P1M')

const next = date.add(oneMonth)
console.log(next.toString()) // '2024-02-29' (constrained to valid date)

const diff = PlainDate.from('2024-01-01').until(PlainDate.from('2024-12-31'))
console.log(diff.days) // 365

// Property bag arguments
const result = date.add({ months: 1, days: 5 })

Timezone-aware Operations

const zdt = Temporal.ZonedDateTime.from('2024-03-09T12:00:00-05:00[America/New_York]')

// Adding 1 day across DST spring-forward
const nextDay = zdt.add({ days: 1 })
console.log(nextDay.hour) // 12 (wall time preserved)

// Convert between timezones
const utc = zdt.withTimeZone('UTC')
console.log(utc.epochMilliseconds === zdt.epochMilliseconds) // true (same instant)

// Start of day
const sod = zdt.startOfDay()
console.log(sod.hour) // 0

// Timezone transitions
const transition = zdt.getTimeZoneTransition('next')

Calendars

16 calendar systems are supported:

// ISO 8601 (default), Gregorian, Japanese, Buddhist, Chinese, Coptic,
// Dangi, Ethiopian, Ethiopic (Amete Alem), Hebrew, Indian,
// Islamic (civil, tabular, Umm al-Qura), Persian, ROC

const date = Temporal.PlainDate.from({
  year: 5784, monthCode: 'M01', day: 1, calendar: 'hebrew'
})
console.log(date.calendarId)  // 'hebrew'
console.log(date.era)         // 'am'
console.log(date.eraYear)     // 5784

Rounding and Comparison

// Round time
const time = new Temporal.PlainTime(13, 45, 30)
const rounded = time.round({ smallestUnit: 'hour', roundingMode: 'halfExpand' })
console.log(rounded.hour)   // 14
console.log(rounded.minute) // 0

// Compare dates
const d1 = new Temporal.PlainDate(2024, 1, 1)
const d2 = new Temporal.PlainDate(2024, 12, 31)
console.log(Temporal.PlainDate.compare(d1, d2)) // -1

// Compute difference with options
const diff = d1.until(d2, { largestUnit: 'month' })
console.log(diff.months) // 11

Type Conversions

// PlainDateTime -> PlainDate + PlainTime
const dt = Temporal.PlainDateTime.from('2024-06-15T10:30:00')
const date = dt.toPlainDate()
const time = dt.toPlainTime()

// ZonedDateTime -> Instant, PlainDate, PlainTime, PlainDateTime
const zdt = Temporal.ZonedDateTime.from('2024-06-15T10:30:00+02:00[Europe/Berlin]')
const instant = zdt.toInstant()
const plainDate = zdt.toPlainDate()
const plainTime = zdt.toPlainTime()
const plainDateTime = zdt.toPlainDateTime()

// PlainDate -> PlainDateTime (with optional time)
const dateOnly = new Temporal.PlainDate(2024, 6, 15)
const withTime = dateOnly.toPlainDateTime(new Temporal.PlainTime(10, 30))

Now Functions

const instant = Temporal.Now.instant()                  // Current Instant
const tz = Temporal.Now.timeZoneId()                    // System timezone ID
const date = Temporal.Now.plainDateISO()                // Current date (local tz)
const time = Temporal.Now.plainTimeISO()                // Current time (local tz)
const dateTime = Temporal.Now.plainDateTimeISO()        // Current date+time (local tz)
const zoned = Temporal.Now.zonedDateTimeISO()           // Current ZonedDateTime (local tz)

// With explicit timezone
const utcDate = Temporal.Now.plainDateISO('UTC')

API Reference

Types

| Class | Description | |-------|-------------| | Temporal.PlainDate | Calendar date (no time, no timezone) | | Temporal.PlainTime | Wall-clock time (no date, no timezone) | | Temporal.PlainDateTime | Calendar date + wall-clock time (no timezone) | | Temporal.ZonedDateTime | Date + time with timezone (DST-aware) | | Temporal.Instant | Exact point in time (epoch nanoseconds) | | Temporal.Duration | ISO 8601 duration with arithmetic | | Temporal.PlainYearMonth | Calendar year + month | | Temporal.PlainMonthDay | Calendar month + day | | Temporal.Now | Current time access |

Imports

// ESM — spec-conforming Temporal namespace (recommended)
import { Temporal } from 'temporal_rs'

// ESM — individual named exports
import { PlainDate, Duration, Instant } from 'temporal_rs'

// CJS — spec-conforming Temporal namespace
const { Temporal } = require('temporal_rs')

// ESM — raw NAPI bindings (no spec conformance layer)
import { PlainDate } from 'temporal_rs/native'

// CJS — raw NAPI bindings
const { PlainDate } = require('temporal_rs/native')

// WASM — for browser/edge runtimes (ESM only)
import { PlainDate } from 'temporal_rs/wasm'

WASM (Browser)

A WASM build is also available for browser use:

npm run build:wasm

This produces a wasm-pkg/ directory with ES module + TypeScript definitions usable via bundlers (webpack, vite, etc).

WASM Limitations

The WASM bindings have some differences from the native Node.js (NAPI) bindings due to wasm-bindgen constraints:

  • Epoch nanosecond precision: Instant and ZonedDateTime constructors accept f64 (JS number) for epoch nanoseconds, which loses precision beyond ±2^53 (~104 days from Unix epoch in nanoseconds). For full nanosecond precision, use Instant.from() or ZonedDateTime.from() with ISO string arguments. The NAPI bindings use BigInt and have no precision loss.
  • epochNanoseconds getter: Returns number (f64) in WASM vs bigint in NAPI. Use epochMilliseconds for a safe numeric value, or toString() for full nanosecond fidelity.
  • toString() display options: ZonedDateTime.toString() and Instant.toString() in WASM do not accept display/rounding options (calendarName, timeZoneName, fractionalSecondDigits, etc.). The NAPI bindings support these options for PlainDateTime.toString() but not yet for ZonedDateTime/Instant.

The pre-built wasm-pkg/ is included in the npm package for convenience. If you only use the Node.js API (import from 'temporal_rs'), the WASM artifacts are unused.

Development

# Install dependencies
npm install

# Build everything (NAPI + TypeScript conformance layer)
npm run build

# Build individual targets
npm run build:napi         # native addon only
npm run build:ts           # TypeScript conformance layer only
npm run build:wasm         # WASM target

# Run unit tests
npm test

# Lint and format
npm run lint               # ESLint (strictTypeChecked)
npm run lint:fix           # auto-fix
npm run format             # Prettier
npm run format:check       # check only

# Run TC39 Test262 Temporal compliance tests (requires test262 submodule)
git submodule update --init
npm run test262

# Run Test262 with filter
npm run test262 -- PlainDate

# Run Test262 verbose (show each test result)
npm run test262:verbose

# Run Test262 and write failure list
npm run test262 -- --write-failures

# Bump version across all packages and lockfiles
./scripts/bump-version.sh patch    # 0.1.1 → 0.1.2
./scripts/bump-version.sh minor    # 0.1.1 → 0.2.0
./scripts/bump-version.sh major    # 0.1.1 → 1.0.0
./scripts/bump-version.sh 2.0.0    # explicit version

Prerequisites

Test262 Compliance

This package includes a runner for the TC39 Test262 Temporal test suite (6,661 tests). The runner executes tests in Node.js vm contexts with the spec conformance layer injected as globalThis.Temporal.

Current results: 6,659 / 6,661 pass (99.97%) — 0 skipped.

The 2 remaining failures are caused by inconsistencies between Node.js's ICU4C and temporal_rs's ICU4X implementations, not by the bindings themselves:

| Test | Root cause | |------|-----------| | format/temporal-objects-resolved-time-zone | Node.js ICU4C format() uses U+0020 before AM/PM but formatToParts() uses U+202F (narrow no-break space). The test compares them. Present in Node.js v22–v25 (ICU 77–78). | | formatToParts/compare-to-temporal-lunisolar | ICU4C and ICU4X disagree on Chinese calendar 2030/M01 start date by 1 day. The new moon falls 7 minutes past midnight Beijing time — ICU4X (temporal_rs) correctly places it on Feb 3, ICU4C on Feb 2. Both are algorithmic ICU bugs that cannot be fixed via ICU data updates. |

How It Works

This package wraps temporal_rs (the Rust implementation used by Boa, Kiesel, and V8) via two binding layers:

  • NAPI-RS for native Node.js addons with hand-crafted TypeScript definitions (aligned with esnext.temporal.d.ts)
  • wasm-bindgen for browser-compatible WASM builds

A modular TypeScript spec conformance layer (lib/) bridges the gap between the NAPI binding surface and the TC39 Temporal specification. It is compiled via tsup to both ESM (.mjs) and CJS (.js) with sourcemaps; hand-crafted type declarations (.d.ts, .d.mts) aligned with TypeScript's esnext.temporal.d.ts provide full type coverage. The conformance layer provides:

  • Temporal namespace with all types and Temporal.Now
  • Property bag arguments for from(), with(), add(), subtract()
  • calendarId / timeZoneId string getters
  • Calendar year-to-ISO conversion for 16 calendar systems
  • Era/eraYear resolution with calendar-specific epoch offsets
  • Proper TypeError / RangeError error types
  • Symbol.toStringTag, Symbol.hasInstance, valueOf() per spec
  • Intl.DateTimeFormat and Intl.DurationFormat integration

Timezone data is embedded in the binary via the zoneinfo64 provider, so no external timezone database is needed.

License

MIT