ponyfill-temporal
v0.1.0
Published
Ponyfill for the TC39 Temporal API that conditionally loads temporal-polyfill only when native Temporal is unavailable.
Maintainers
Readme
ponyfill-temporal
A ponyfill for the TC39 Temporal API.
It uses the runtime's native globalThis.Temporal when available, and otherwise
conditionally loads temporal-polyfill
via a dynamic import(). The polyfill is only pulled into your bundle/runtime
when native Temporal is absent.
The stack
- Types:
temporal-spec— a runtime-free, types-only package that models the native Temporal API. This package's public types are sourced from it. - Runtime fallback:
temporal-polyfill(fromfullcalendar) — lightweight, actively maintained, and it already types its own exports againsttemporal-spec.
Because the polyfill's runtime is typed against the same spec that models native
Temporal, the native and polyfilled Temporal / toTemporalInstant values share
one type — no casting between "native Temporal" and "polyfill Temporal".
Ponyfill vs. polyfill
A polyfill mutates the global environment (e.g. it assigns
globalThis.Temporal). A ponyfill provides the same functionality without
touching any globals — you import what you need and use it directly.
ponyfill-temporal is a ponyfill by default: loadTemporal() returns the
Temporal API without mutating globalThis. If native Temporal already exists,
the polyfill is never even loaded, so runtimes that ship Temporal pay zero cost.
A polyfill-style convenience (installTemporal()) is also provided for the rare
case where you genuinely want the global side effect.
Installation
npm install ponyfill-temporal
# or
bun add ponyfill-temporaltemporal-polyfill and temporal-spec are dependencies. temporal-spec is
types-only (its runtime entry is empty), and temporal-polyfill is only ever
evaluated (via a lazy dynamic import()) when the runtime does not provide
native Temporal.
Usage
loadTemporal() — the pure ponyfill (recommended)
import { loadTemporal } from "ponyfill-temporal";
const { Temporal, Intl, toTemporalInstant } = await loadTemporal();
const today = Temporal.Now.plainDateISO();
console.log(today.toString());loadTemporal() returns the temporal-polyfill export surface (which mirrors
native Temporal):
| Export | Description |
| ------------------- | ------------------------------------------------------------- |
| Temporal | The Temporal namespace object. |
| Intl | The Temporal-aware Intl namespace object. |
| toTemporalInstant | The function installed as Date.prototype.toTemporalInstant. |
Because loading is asynchronous (the polyfill is imported lazily), loadTemporal
returns a Promise. Resolve it once at startup and share the result.
isNativeTemporalAvailable()
import { isNativeTemporalAvailable } from "ponyfill-temporal";
if (isNativeTemporalAvailable()) {
// Running on a runtime that ships Temporal natively.
}installTemporal() — polyfill-style global install (opt-in)
import { installTemporal } from "ponyfill-temporal";
// Assigns globalThis.Temporal (and Date.prototype.toTemporalInstant)
// only if native Temporal is not already present.
await installTemporal();
// Now available globally.
const now = Temporal.Now.instant();Prefer loadTemporal() unless you specifically need the global side effect.
Why conditional loading?
Importing temporal-polyfill unconditionally would always ship the polyfill,
defeating the purpose on runtimes that already implement Temporal. loadTemporal
checks typeof globalThis.Temporal first and only performs
await import("temporal-polyfill") when native Temporal is missing — so the
polyfill stays out of the hot path (and, with a bundler that supports it, out of
the initial chunk) whenever the platform provides Temporal.
License
Apache-2.0
