Volver al blog

ES2026 y Temporal API: Finalmente JavaScript Tendrá Manipulación de Fechas Nativa y Decente

Hola HaWkers, después de años dependiendo de bibliotecas externas como moment.js y date-fns, finalmente JavaScript tendrá una API de fechas nativa que tiene sentido. La Temporal API llegó al Stage 4 y será oficialmente parte de ES2026, marcando una de las mayores evoluciones del lenguaje en los últimos años.

¿Por qué la comunidad JavaScript esperó tanto por esto? ¿Y qué cambia en la práctica para los desarrolladores?

El Problema Histórico de Date

El objeto Date de JavaScript es famoso por sus inconsistencias.

Problemas Clásicos

Por qué Date es problemático:

// Problema 1: Los meses empiezan en 0
const date = new Date(2026, 0, 15); // Enero = 0, no 1
console.log(date); // 15 de Enero de 2026

// Problema 2: Mutabilidad peligrosa
const original = new Date(2026, 5, 15);
const modified = original;
modified.setMonth(7); // ¡Modifica AMBAS variables!
console.log(original); // ¡Agosto, no Junio!

// Problema 3: Parsing inconsistente
new Date('2026-01-15'); // Interpretado como UTC
new Date('01/15/2026'); // Interpretado como local
// ¡Resultados diferentes dependiendo del timezone!

// Problema 4: Sin soporte de timezones
const date2 = new Date();
// ¿Cómo convertir al timezone de Tokyo?
// Necesita biblioteca externa o cálculos manuales

Temporal API: La Solución

Inmutable, precisa e intuitiva.

Tipos Principales

Objetos disponibles en Temporal:

// Temporal.PlainDate - Solo fecha, sin hora o timezone
const date = Temporal.PlainDate.from('2026-01-15');
console.log(date.year);  // 2026
console.log(date.month); // 1 (¡Enero = 1, finalmente!)
console.log(date.day);   // 15

// Temporal.PlainTime - Solo hora, sin fecha
const time = Temporal.PlainTime.from('14:30:00');
console.log(time.hour);   // 14
console.log(time.minute); // 30

// Temporal.PlainDateTime - Fecha y hora, sin timezone
const dateTime = Temporal.PlainDateTime.from('2026-01-15T14:30:00');

// Temporal.ZonedDateTime - Fecha, hora Y timezone
const zonedDT = Temporal.ZonedDateTime.from({
  timeZone: 'America/Mexico_City',
  year: 2026,
  month: 1,
  day: 15,
  hour: 14,
  minute: 30
});

// Temporal.Instant - Punto exacto en el tiempo (timestamp)
const instant = Temporal.Instant.from('2026-01-15T17:30:00Z');

// Temporal.Duration - Duración de tiempo
const duration = Temporal.Duration.from({ hours: 2, minutes: 30 });

Operaciones Inmutables

Nunca más modificar accidentalmente:

const date = Temporal.PlainDate.from('2026-01-15');

// Agregar días retorna NUEVA instancia
const nextWeek = date.add({ days: 7 });
console.log(date.toString());     // 2026-01-15 (original intacto)
console.log(nextWeek.toString()); // 2026-01-22 (nueva instancia)

// Restar tiempo
const lastMonth = date.subtract({ months: 1 });
console.log(lastMonth.toString()); // 2025-12-15

// Modificar campos específicos
const newYear = date.with({ year: 2027 });
console.log(newYear.toString()); // 2027-01-15

// Comparaciones directas
const date1 = Temporal.PlainDate.from('2026-01-15');
const date2 = Temporal.PlainDate.from('2026-02-20');

console.log(Temporal.PlainDate.compare(date1, date2)); // -1 (date1 < date2)
console.log(date1.equals(date2)); // false

Timezones Finalmente Resueltos

Conversiones sin dolor de cabeza.

Trabajando con Zonas Horarias

// Crear fecha con timezone específico
const mxDateTime = Temporal.ZonedDateTime.from({
  timeZone: 'America/Mexico_City',
  year: 2026,
  month: 1,
  day: 15,
  hour: 10,
  minute: 0
});

console.log(mxDateTime.toString());
// 2026-01-15T10:00:00-06:00[America/Mexico_City]

// Convertir a otro timezone
const tokyoDateTime = mxDateTime.withTimeZone('Asia/Tokyo');
console.log(tokyoDateTime.toString());
// 2026-01-16T01:00:00+09:00[Asia/Tokyo]

// Mismo instante, diferentes representaciones locales
console.log(mxDateTime.toInstant().equals(tokyoDateTime.toInstant())); // true

// Obtener offset actual
console.log(mxDateTime.offset); // -06:00

// Listar todos los timezones disponibles
const timezones = Temporal.TimeZone.getAvailableTimeZones();
console.log(timezones.includes('America/Mexico_City')); // true

Horario de Verano

Manejo automático de DST:

// Temporal maneja automáticamente el horario de verano
const beforeDST = Temporal.ZonedDateTime.from({
  timeZone: 'America/New_York',
  year: 2026,
  month: 3,
  day: 8,
  hour: 1,
  minute: 30
});

// Agregar 2 horas atravesando cambio de DST
const afterDST = beforeDST.add({ hours: 2 });
console.log(afterDST.hour); // 4 (no 3, porque saltó una hora)

// Verificar si está en horario de verano
console.log(beforeDST.inDST); // false
console.log(afterDST.inDST);  // true

Duration: Cálculos de Período

Intervalos y duraciones precisas.

Operaciones con Duración

// Crear duración
const duration = Temporal.Duration.from({
  years: 1,
  months: 2,
  days: 15,
  hours: 8,
  minutes: 30
});

console.log(duration.total('days')); // Total aproximado en días

// Diferencia entre fechas
const start = Temporal.PlainDate.from('2026-01-15');
const end = Temporal.PlainDate.from('2026-06-20');

const diff = start.until(end);
console.log(diff.months); // 5
console.log(diff.days);   // 5

// Especificar unidades deseadas
const diffInDays = start.until(end, { largestUnit: 'day' });
console.log(diffInDays.days); // 156

// Redondear duración
const preciseDuration = Temporal.Duration.from({
  hours: 2,
  minutes: 45,
  seconds: 30
});

const rounded = preciseDuration.round({
  smallestUnit: 'minute',
  roundingMode: 'halfExpand'
});
console.log(rounded.minutes); // 46

Aplicación Práctica: Countdown

function getCountdown(targetDate) {
  const now = Temporal.Now.plainDateTimeISO();
  const target = Temporal.PlainDateTime.from(targetDate);

  if (Temporal.PlainDateTime.compare(now, target) >= 0) {
    return { expired: true };
  }

  const duration = now.until(target, {
    largestUnit: 'day'
  });

  return {
    expired: false,
    days: duration.days,
    hours: duration.hours,
    minutes: duration.minutes,
    seconds: duration.seconds
  };
}

const countdown = getCountdown('2026-12-31T23:59:59');
console.log(`${countdown.days}d ${countdown.hours}h ${countdown.minutes}m`);

Comparación: Temporal vs Bibliotecas

Adiós dependencias innecesarias.

Antes (con date-fns)

import {
  format,
  addDays,
  differenceInDays,
  parseISO,
  isAfter
} from 'date-fns';
import { zonedTimeToUtc, utcToZonedTime } from 'date-fns-tz';

const date = parseISO('2026-01-15');
const nextWeek = addDays(date, 7);
const formatted = format(nextWeek, 'dd/MM/yyyy');

// Timezone requiere paquete adicional
const mxTime = utcToZonedTime(new Date(), 'America/Mexico_City');

Después (con Temporal)

// Nativo, sin imports
const date = Temporal.PlainDate.from('2026-01-15');
const nextWeek = date.add({ days: 7 });
const formatted = nextWeek.toLocaleString('es-MX');

// Timezone nativo
const mxTime = Temporal.Now.zonedDateTimeISO('America/Mexico_City');

Comparativo de Bundle Size

Impacto en el tamaño del proyecto:

Biblioteca Tamaño (minified) Con Temporal
moment.js 72 KB 0 KB
date-fns (full) 85 KB 0 KB
dayjs 7 KB 0 KB
luxon 68 KB 0 KB
Temporal Nativo 0 KB

💡 Nota: Temporal es nativo del browser/runtime, por lo que no agrega nada al bundle size de tu aplicación.

Casos de Uso Prácticos

Ejemplos del mundo real.

Programación de Reuniones Globales

function scheduleGlobalMeeting(participants) {
  // Cada participante con su timezone
  const schedules = participants.map(p => ({
    name: p.name,
    timezone: p.timezone,
    workStart: Temporal.PlainTime.from('09:00'),
    workEnd: Temporal.PlainTime.from('18:00')
  }));

  // Encontrar horario que funcione para todos
  const referenceDate = Temporal.Now.plainDateISO();

  for (let hour = 0; hour < 24; hour++) {
    const testTime = Temporal.PlainDateTime.from({
      year: referenceDate.year,
      month: referenceDate.month,
      day: referenceDate.day,
      hour: hour,
      minute: 0
    });

    const worksForAll = schedules.every(s => {
      const localTime = testTime
        .toZonedDateTime('UTC')
        .withTimeZone(s.timezone)
        .toPlainTime();

      return Temporal.PlainTime.compare(localTime, s.workStart) >= 0 &&
             Temporal.PlainTime.compare(localTime, s.workEnd) <= 0;
    });

    if (worksForAll) {
      return { hour, suitable: true };
    }
  }

  return { suitable: false };
}

Adopción y Compatibilidad

Cuándo y cómo usar.

Estado Actual

Disponibilidad en 2026:

Navegadores:

  • Chrome 144+: Soporte completo
  • Firefox: En desarrollo
  • Safari: En desarrollo

Runtimes:

  • Node.js 24+: Soporte completo
  • Deno: Soporte completo
  • Bun: Soporte completo

Polyfill disponible:

npm install @js-temporal/polyfill
// Usar polyfill mientras los navegadores actualizan
import { Temporal } from '@js-temporal/polyfill';

const now = Temporal.Now.plainDateTimeISO();

Migración Gradual

Estrategia de transición:

// Wrapper para migración gradual
function toTemporal(date) {
  if (date instanceof Date) {
    return Temporal.Instant
      .fromEpochMilliseconds(date.getTime())
      .toZonedDateTimeISO('UTC');
  }
  return date;
}

function toDate(temporal) {
  if (temporal instanceof Temporal.ZonedDateTime) {
    return new Date(temporal.epochMilliseconds);
  }
  return temporal;
}

// Uso durante migración
const legacyDate = new Date();
const temporal = toTemporal(legacyDate);
// ... operaciones con Temporal
const backToDate = toDate(temporal);

ES2026 con Temporal API representa una de las mayores evoluciones de JavaScript. Finalmente tendremos manipulación de fechas que tiene sentido, es inmutable por defecto y soporta timezones nativamente. Si todavía estás usando moment.js o date-fns para operaciones básicas, prepárate para simplificar mucho tu código muy pronto.

Si quieres profundizar en las novedades del JavaScript moderno, te recomiendo ver otro artículo: Signals: El Nuevo Estándar de Reactividad de JavaScript donde descubrirás cómo la reactividad está evolucionando en el lenguaje.

¡Vamos con todo! 🦅

📚 ¿Quieres Profundizar tus Conocimientos en JavaScript?

Este artículo cubrió la Temporal API, pero hay mucho más por explorar en el mundo del desarrollo moderno.

Los desarrolladores que invierten en conocimiento sólido y estructurado tienden a tener más oportunidades en el mercado.

Material de Estudio Completo

Si quieres dominar JavaScript desde lo básico hasta lo avanzado, he preparado una guía completa:

Opciones de inversión:

  • 1x de $4.90 con tarjeta
  • o $4.90 al contado

👉 Conocer la Guía JavaScript

💡 Material actualizado con las mejores prácticas del mercado

Comentarios (0)

Este artículo aún no tiene comentarios 😢. ¡Sé el primero! 🚀🦅

Añadir comentarios