
*By Sean Erick C. Ramones, Vue SME | JavaScript/TypeScript SME*
Sean Erick C. Ramones
For decades, the JavaScript Date object has been the "Achilles' heel" of the language, as it’s mutable, lacks timezone intelligence, and is generally unpredictable. This forced us to rely on heavy libraries like Moment.js or utility sets like date-fns.
As of early 2026, the Temporal API has reached stable, native support across all major evergreen browsers. It provides a modern, developer-friendly, and immutable way to handle date and time. For our team, this means smaller bundle sizes, fewer "off-by-one" bugs, and cleaner code.
Temporal doesn't just give us one "Date" object; it gives us specialized types for specific needs. This prevents us from accidentally using a timezone where we only need a calendar date.
Temporal.Instant: A fixed point in time (UTC).Temporal.PlainDate: A date with no time or timezone (e.g., "2026-05-12").Temporal.ZonedDateTime: A date and time within a specific timezone.Temporal.Durationem: For math (e.g., "add 2 hours and 5 minutes").How does our current logic stack up against the new native standard?
| Feature | Moment.js | date-fns | Temporal (Native) |
|---|---|---|---|
| Mutability | ❌ Mutable (Risky) | ✅ Immutable | ✅ Immutable |
| Timezones | ⚠️ Needs Plugin | ⚠️ Needs Plugin | ✅ Built-in (IANA) |
| Bundle Size | ❌ ~200KB | ✅ Tree-shakable | ✅ 0KB (Native) |
| Arithmetic | .add(1, 'day') | addDays(date, 1) | date.add({ days: 1 }) |
Legacy (Moment):
JavaScript
const delivery = moment().add(7, 'days');
if (delivery.isAfter(moment())) { /* ... */ }
Modern (Temporal):
TypeScript
const today = Temporal.Now.plainDateISO();
const delivery = today.add({ days: 7 });
if (Temporal.PlainDate.compare(delivery, today) > 0) {
// Logic is clean, native, and type-safe
}
Currently, Preesh uses @internationalized/date (via React Aria). While this library served us well, it’s an extra dependency we can eventually phase out.
@internationalized/date objects like CalendarDate are proprietary. They don’t play well with standard JS methods or third-party logging without conversion.
We cannot replace @internationalized/date in our UI components (like the DatePicker) because they are strictly typed. However, we should move all Business Logic to Temporal.
Example: Calculating a Discount Expiry in Preesh
TypeScript
// 1. Do the heavy lifting in Native Temporal
const dateStart= Temporal.Now.plainDateISO();
const dateEnd = dateStart.add({ weeks: 2 });
// 2. Bridge to the UI (if needed for a Calendar component)
const uiDate = new CalendarDate(dateEnd.year, dateEnd.month, dateEnd.day);
// 3. Logic remains clean
const daysLeft = dateStart.until(dateEnd).days;
dateA will never be accidentally changed by a function calculating dateB.@js-temporal/polyfill).Date object because it is more precise.My recommendation is we start a "Soft Migration" in Preesh:
src/utils.@internationalized/date exclusively for the value props of UI components.package.json to see if we can remove any old date utility libraries to save bundle space.