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.
temporal-spec — a
runtime-free, types-only package that models the native Temporal API. This
package's public types are sourced from it.temporal-polyfill
(from fullcalendar) — lightweight, actively maintained, and it already types
its own exports against temporal-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".
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.
npm install ponyfill-temporal
# or
bun add ponyfill-temporal
temporal-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.
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.
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.
Apache-2.0