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
momentAPIs with Temporal equivalents. - Remove
moment/moment-timezone/luxonimports 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')toTemporal.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 withIntl.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, orPOLYFILL=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.jsonor handle runtime polyfill loading. You must manage those separately after migration.