Library / SDK
fullcalendar/temporal-polyfill avatar
fullcalendar/temporal-polyfill

temporal-polyfill, a spec-compliant Temporal for JavaScript that you can delete later

A lightweight polyfill for Temporal, successor to the JavaScript Date object

783 stars30 forksTypeScriptLicense varies

At a glance

What is it?
fullcalendar/temporal-polyfill is a monorepo whose headliner package is a sub 20 kB polyfill for the Temporal API, plus a tree-shakeable function API for library authors, a codemod that rewrites that API into native Temporal calls, standalone TypeScript types and a small helper package. The pitch is that a component library can depend on it without forcing a polyfill on its users.
Who is it for?
Adopt temporal-polyfill if your application needs date and time handling that avoids the Date object and you have browsers in the support matrix without native Temporal. For a component library, adopt the tree-shakeable API as a peer dependency rather than bundling the polyfill, so your users keep the choice of whether to load it.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The polyfill itself and its entrypoints

Temporal is the successor to the JavaScript Date object, and native support is still incomplete. The temporal-polyfill package is the headliner of this monorepo, described as a lightweight, spec-compliant polyfill of less than 20 kB.

The install is the usual npm line:

sh
npm install temporal-polyfill

The most common entrypoint installs the global:

js
import 'temporal-polyfill/global' // most common entrypoint

Temporal.Now.zonedDateTimeISO().toString()
// '2026-06-18T13:45:00-04:00[America/New_York]'

Note what that output shows. The result is a zoned date time string that carries both the offset and the IANA zone identifier in square brackets, which is the behaviour that Date cannot express. Once a date is bound to a zone it stays bound to that zone through arithmetic, and that is the difference the whole Temporal proposal is about.

The package documentation mentions other entrypoints, CDN usage, an expanded-calendar build under a /full/ path for non-Gregorian calendar systems, and TypeScript setup. The README notes that Safari and older environments still lack native Temporal, which is the reason a polyfill exists at all rather than a transitional nicety.

The repository is a pnpm workspace with the preinstall hook enforcing pnpm via npx only-allow pnpm, lefthook for git hooks, biome for formatting and linting, and separate packages under polyfill/, codemod/, utils/ and spec/. There is a test262 directory, which is the official ECMAScript test suite, so the polyfill is measured against the spec rather than against hand-written assertions.

The tree-shakeable function API and the problem it solves for libraries

The second entrypoint is the one that makes this project more than a polyfill. Every Temporal operation is also exposed as a standalone function acting on a plain record, so a bundler keeps only the functions actually imported:

js
import * as PlainDateFns from 'temporal-polyfill/fns/PlainDate'

const date = PlainDateFns.create(2026, 6, 1)
const later = PlainDateFns.addMonths(date, 2)

PlainDateFns.toString(later) // '2026-08-01'

Each Temporal type has its own entrypoint under temporal-polyfill/fns/*, such as temporal-polyfill/fns/ZonedDateTime.

The problem this solves is spelled out in the README as the date-library dilemma. A component author has three bad options: bundle dayjs or date-fns into every consuming app, hand-roll helpers around Date, or pull in an adapter like date-io and make users pick a library. All three push another date library into every application that installs the component.

The proposed answer is to depend on temporal-polyfill as a peer dependency and import only the needed functions, leaving the decision to load the full polyfill to the host application. The README includes an ASCII diagram showing an app importing the global entrypoint optionally, a date picker component importing only the functions it needs, and both resolving to one shared copy of the internals rather than two.

The second half of the argument is that this is a dependency you can delete. When native Temporal reaches the browsers you target, the codemod rewrites the code into idiomatic Temporal calls and the dependency falls away, because each function maps one to one onto its Temporal equivalent.

The codemod that removes the dependency later

The codemod package converts code written against the tree-shakeable API into idiomatic Temporal, producing real Temporal objects and their methods:

sh
npx temporal-polyfill-codemod fns-to-temporal <path>

The before and after is a mechanical change. The function call PlainDateFns.create(2024, 5, 1) becomes new Temporal.PlainDate(2024, 5, 1), and PlainDateFns.addDays(date, 3) becomes date.add({ days: 3 }). Note the shape change as well as the name change, since the options object is how Temporal methods express units.

What makes this trustworthy rather than hopeful is the conservative policy. The README says anything the transform cannot unambiguously rewrite is left untouched and reported as a migration-blocking diagnostic, so CI catches an incomplete migration. A codemod that silently guesses produces a broken build in a way that is hard to trace back to the migration; one that refuses and reports gives you a list to work through.

The current transform is named fns-to-temporal, which suggests the intent is incremental. You adopt the tree-shakeable functions first because they fit a component library's constraints, then migrate when the runtime supports it natively, one file at a time if necessary.

The temporal-utils package completes the set. It provides everyday operations that Temporal itself does not ship, such as startOfMonth, endOfDay, diffDays and roundToWeek, and most helpers preserve the input type, returning a PlainDate for a PlainDate input and a ZonedDateTime for a ZonedDateTime input. Unlike the tree-shakeable API, these helpers operate on the idiomatic Temporal objects, and they expect a global Temporal at runtime.

Standalone types, workspace layout and the tooling

The temporal-spec package holds standalone TypeScript type definitions for Temporal with no runtime code at all. It describes the shape of the Temporal API and the Temporal-related additions to Intl and Date, so any implementation, polyfill or application can share one accurate set of types. It is published separately so that consumers are not forced to depend on the polyfill package just to get correct types.

The workspace root package.json names the author as Adam Shaw and sets the licence to MIT for the workspace. The scripts define a straightforward pipeline: ci runs clean, lint, build and test in sequence; lint, build and clean each fan out across packages with pnpm -r; and test runs recursively while filtering out the terser package, which is overridden to the workspace version.

There is also a separate vitest script for running the unit tests directly and a test262 script for running the spec suite, and the test262 directory at the top level is a git submodule, given the .gitmodules file.

The repository is active. The last push was on 2026-10-13 and the releases show temporal-polyfill at 1.0.6 on the same day, with 1.0.5 and temporal-utils 1.0.3 both on 2026-09-11. The 1.0 release is the significant one, since it is the point at which the API can be relied upon rather than changed under you. The licence field on the repository says it is unknown, which is worth resolving before you ship it in a commercial product, since the workspace package.json declares MIT but the repository-level metadata does not.

How this compares with dayjs, date-fns and a hand-rolled Date wrapper

The alternatives for JavaScript date handling are well known, and the difference in approach is about what the library commits you to.

dayjs is tiny and immutable with a Moment-like API, which makes it cheap in bundle terms but leaves it working in a Date-shaped world. date-fns is tree-shakeable and functional, but its types are its own and its objects are its own, so a component library using it forces its own date model on the consumer. A hand-rolled wrapper around Date keeps zero dependencies but inherits every Date problem, including the mutable object, the ambiguous month index and the absence of any zone concept.

Temporal changes the shape of the answer. It is built into the language and the platform, so the end state is a native API rather than a library that has to keep pace with it. The polyfill exists to get there earlier, and the tree-shakeable function API plus the codemod exist to make that transition cheap for library authors who cannot dictate what their consumers install.

That middle ground is the real differentiator. Most date libraries want to be your date library forever. This project explicitly plans to be deleted, and the README argues the case for the shared standard: Temporal is something component libraries can all agree on without each shipping their own copy.

The cost is that Temporal has more surface area than Date, and the polyfill adds bytes to a bundle. Whether that trade is worth it depends on whether your application actually does time zone and calendar work. For a scheduling application, a booking system, or anything that must survive a daylight saving transition, the reasoning holds. For a form that validates a date of birth, it is overkill.

Editorial conclusion

Adopt temporal-polyfill if your application needs date and time handling that avoids the Date object and you have browsers in the support matrix without native Temporal. For a component library, adopt the tree-shakeable API as a peer dependency rather than bundling the polyfill, so your users keep the choice of whether to load it. Skip it if you only need simple date arithmetic, since Date with a small helper library still covers that with less weight. Verify first by installing the package, importing temporal-polyfill/global in a test build, and running the codemod on a small part of your codebase to see how much of it converts cleanly.

Frequently asked questions

How do I install and use the temporal-polyfill?

Install it with npm install temporal-polyfill, then import the global entrypoint with import 'temporal-polyfill/global'. After that the Temporal object is available and Temporal.Now.zonedDateTimeISO() returns a zoned date time string carrying an offset and an IANA zone identifier.

What is the tree-shakeable function API in temporal-polyfill?

It exposes every Temporal operation as a standalone function acting on a plain record, under per-type entrypoints such as temporal-polyfill/fns/PlainDate. A bundler keeps only the imported functions, which lets a component library use Temporal dates without forcing the full polyfill on its users.

How do I migrate away from the temporal-polyfill later?

Run npx temporal-polyfill-codemod fns-to-temporal against the path to convert. The transform is deliberately conservative: anything it cannot unambiguously rewrite is left alone and reported as a migration-blocking diagnostic so CI catches an incomplete migration.

What does temporal-utils add on top of Temporal?

It provides convenience helpers for the idiomatic Temporal API that Temporal itself does not ship, including startOfMonth, endOfDay, diffDays and roundToWeek. Most helpers preserve the input type, and the package operates on a global Temporal so it needs the polyfill or native Temporal at runtime.

Is there a standalone TypeScript type package for Temporal?

Yes, temporal-spec contains only .d.ts files with no runtime code, describing the Temporal API along with the Temporal-related additions to Intl and Date. It is published separately so consumers can get accurate types without depending on the polyfill package.

Official sources

  1. fullcalendar/temporal-polyfill on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fullcalendar-temporal-polyfill.svg)](https://hysenlabs.com/projects/fullcalendar-temporal-polyfill)

Was this useful?