moment to Temporal
This codemod migrates common moment and moment-timezone usage to Temporal equivalents. It rewrites frequently used patterns such as “now”, add/subtract chains, simple formatting, parsing, durations, timezone conversion, and validation checks.
It also supports migrating a limited Luxon entrypoint (DateTime.local()) to Temporal in mixed codebases.
Goal
- Replace common moment APIs with Temporal equivalents.
- Remove moment / moment-timezone / luxon imports when transformed.
- Keep transformed code explicit and readable.
- Cover common migration paths while surfacing edge cases for review.
Example
Replace moment() + .format()
diff
Replace add/subtract chaining
diff
Replace simple date formatting (YYYY-MM-DD)
diff
Replace moment.tz(...)
diff
Replace locale token formatting (LL)
diff
Replace moment.duration(...)
diff
What this codemod currently covers
- moment() creation and .format() default usage.
- .add(...) / .subtract(...) chains with common units.
- format('YYYY-MM-DD') to Temporal.Now.plainDateISO().toString().
- Parsing patterns:
- moment('12/31/2020', 'MM/DD/YYYY')
- moment('2020-01-02', 'YYYY-MM-DD')
- Timezone pattern: moment.tz(datetime, timezone).
- Unix epoch pattern: moment.unix(seconds).
- Relative time pattern: .fromNow() (rewritten with Intl.RelativeTimeFormat).
- Differences pattern: .diff(..., unit) for covered units.
- Validation patterns:
- moment('bad').isValid()
- strict parse shape moment(value, 'YYYY-MM-DD', true).isValid()
- Edge helpers for ordinals, quarters, weeks, start/end of day, UTC/local combinations.
- moment.duration({...}) and add-duration flows.
- Limited Luxon migration: DateTime.local() and .toISO().
Usage
Enable optional Temporal polyfill import insertion via workflow param:
- Param: importPolyfill=true
- Env (supported aliases): IMPORT_POLYFILL=true, CODEMOD_IMPORT_POLYFILL=true, or POLYFILL=true
When enabled, the transform attempts to inject:
- ESM: import { Temporal } from '@js-temporal/polyfill';
- CJS: const { Temporal } = require('@js-temporal/polyfill');
Caveats
- This codemod focuses on known patterns from fixtures and may skip unsupported call shapes.
- Token-rich moment.format(...) cases beyond covered patterns need manual migration.
- Temporal timezone ambiguity resolution (e.g. DST folds/skips) may require project-specific policy.
- Relative time wording can differ from Moment output because it uses Intl.RelativeTimeFormat.
- Always review transformed code and run your app/tests after migration.
- This codemod does not attempt to remove dep of your package.json or handle runtime polyfill loading. You must manage those separately after migration.