Replaces date-fns and date-fns-tz usages with Temporal API equivalents, with an optional AI-assisted fallback for unsupported patterns.
AugustinMauroy·4 executions
transformation
migration
date-fns
date-fns-tz
temporal
date-fns to Temporal
This codemod migrates common date-fns and date-fns-tz usage to Temporal equivalents. It rewrites a focused set of high-confidence patterns such as creating “now”, adding days, simple formatting, custom parsing, and timezone conversion.
It supports optional Temporal polyfill import insertion for environments that need it.
It also supports an optional AI-assisted fallback pass for unsupported date-fns / date-fns-tz patterns that remain after deterministic AST transforms.
Goal
Replace common date-fns / date-fns-tz APIs with Temporal equivalents.
Remove transformed date-fns / date-fns-tz imports where safe.
Keep transformed code explicit and readable.
Cover practical migration paths while surfacing unsupported patterns for manual review.
Example
Replace format(new Date(), 'yyyy-MM-dd')
diff
- const { format } = require('date-fns');
- const s = format(new Date(), 'yyyy-MM-dd');
+ const s = Temporal.Now.plainDateISO().toString();
Replace addDays(new Date(), n)
diff
- const addDays = require('date-fns/addDays');
- const next = addDays(new Date(), 3);
- console.log(next);
+ let z = Temporal.Now.zonedDateTimeISO();
+ z = z.plus({ days: 3 });
+ console.log(z.toString());
Replace subDays(new Date(), n)
diff
- const subDays = require('date-fns/subDays');
- const prev = subDays(new Date(), 3);
- console.log(prev);
+ let z = Temporal.Now.zonedDateTimeISO();
+ z = z.subtract({ days: 3 });
+ console.log(z.toString());
Replace addYears(new Date(), n)
diff
- const addYears = require('date-fns/addYears');
- const future = addYears(new Date(), 2);
- console.log(future);
+ let z = Temporal.Now.zonedDateTimeISO();
+ z = z.plus({ years: 2 });
+ console.log(z.toString());
Replace format(new Date(), 'PP')
diff
- const { format } = require('date-fns');
- const s = format(new Date(), 'PP');
+ const dt = Temporal.Now.plainDateTimeISO();
+ const s = new Intl.DateTimeFormat(undefined, { dateStyle: 'long' }).format(dt);
parse(value, 'MM/dd/yyyy', new Date()), including literal-string call-expression contexts.
utcToZonedTime(new Date(epochMs), timezone), including broader call-expression contexts.
Import cleanup for transformed date-fns and date-fns-tz usages.
Still unsupported (manual migration required)
formatDistance(date1, date2, [options]) — no direct Temporal equivalent. Use Intl.RelativeTimeFormat with manual duration calculation.
formatRelative(date, baseDate, [options]) — locale-dependent relative formatting has no clean Temporal mapping. Build relative output manually with Temporal.PlainDate.until() and Intl.RelativeTimeFormat.
Any date arithmetic API called with a variable/existing Date instead of new Date() (e.g., subDays(existingDate, n)) — convert the source Date to a Temporal.Instant or Temporal.ZonedDateTime first, then apply .add()/.subtract().
Low-confidence inputs are intentionally not rewritten deterministically (for example addDays(existingDateVar, n) or parse(dynamicInput, 'MM/dd/yyyy', new Date()) where the parsed value is not a literal string).
Manual guidance for unsupported leftovers:
For addDays(existingDateVar, n), convert the source Date to a Temporal.Instant (or zoned value) first, then apply .plus({ days: n }).
For parse(dynamicInput, 'MM/dd/yyyy', new Date()), validate input shape, split into month/day/year parts, then build Temporal.PlainDate.from(...).
For unsupported format(...) token patterns, map tokens to Intl.DateTimeFormat options or Temporal field access explicitly.
Temporal API usage may still require project-level runtime decisions (native Temporal vs polyfill).
AI fallback currently includes deterministic fixture-backed rewrites plus TODO annotations for unsupported shapes.
Always review transformed code and run your app/tests after migration.
Ready to evolve your codebase?
Build tailored, compiler-aware skills to assess, plan, and automate complex codebase changes.