- Señala la incompletitud e inconsistencia del objeto
Date existente en JavaScript e introduce la API Temporal como su reemplazo
Date funciona como un objeto mutable (mutable object), lo que no encaja con el concepto real de fecha, y además tiene problemas estructurales como errores de parseo y limitaciones en el manejo de zonas horarias
Temporal ofrece un nuevo modelo para manejar fecha y hora basado en inmutabilidad, e incluye clases más específicas como PlainDate, ZonedDateTime y Duration
- Los métodos de
Temporal no modifican el objeto existente, sino que devuelven un nuevo objeto, lo que permite operaciones encadenadas más claras y seguras
Temporal se encuentra actualmente en la etapa 3 de estandarización (Stage 3) y ya cuenta con soporte experimental en navegadores modernos como Chrome y Firefox
Problemas del objeto Date de JavaScript
- El constructor
Date genera confusión por sus reglas de parseo inconsistentes y su indexación poco intuitiva
- Ejemplo: el mes (
month) empieza en 0, mientras que el día (day) y el año (year) empiezan en 1
- La cadena
"99" se interpreta como 1999, mientras que "100" se interpreta como el año 0100, lo que demuestra la falta de consistencia
Date está diseñado con énfasis en el tiempo (time) y almacena internamente un timestamp Unix (en milisegundos)
- El soporte de zona horaria (time zone) es limitado y no reconoce correctamente el horario de verano (DST) ni los calendarios no gregorianos
- Por estas limitaciones, es común depender de grandes librerías de terceros como Moment.js o date-fns, lo que puede traducirse en peor rendimiento
Conflicto entre inmutabilidad y referencias
- En JavaScript, los valores primitivos (primitive) son inmutables y se almacenan por valor, mientras que los objetos (object) se almacenan por referencia (
reference) y pueden modificarse
Date es un objeto creado mediante un constructor (constructor), por lo que es mutable
- Ejemplo: al llamar
setMonth() o setDate(), el objeto original se modifica directamente
- Esto provoca cambios inesperados en el valor entre variables que apuntan al mismo objeto
- Ejemplo: si una función recibe
today como argumento y modifica la fecha internamente, el today original también cambia
Temporal: una nueva API de fecha y hora
Temporal es un objeto de espacio de nombres (namespace object), no un constructor, con una estructura similar a Math
- Componentes principales:
PlainDate, PlainDateTime, PlainTime, ZonedDateTime, Duration, Now, etc.
Temporal.Now devuelve el momento actual en distintos formatos
plainDateISO() → fecha en formato ISO
zonedDateTimeISO() → fecha y hora con zona horaria
- Los objetos de
Temporal ofrecen un sistema de métodos claro
- Permiten operaciones con unidades explícitas como
add({ days: 1 }) y subtract({ years: 2 })
- No modifican el objeto existente, sino que devuelven uno nuevo, manteniendo la inmutabilidad
Cómo funciona Temporal y cuáles son sus ventajas
- Los objetos de
Temporal siguen siendo objetos, pero usan un patrón de uso intencionalmente inmutable
- Ejemplo:
today.add({ days: 1 }) devuelve un nuevo objeto de fecha, mientras que el today original no cambia
- Ofrece una sintaxis más concisa y clara que
Date
- Responde mejor a necesidades modernas como la definición de zonas horarias, el cálculo de períodos y el mantenimiento del formato ISO
- Con encadenamiento de métodos como
add, subtract, since y until, es posible expresar de forma concisa cálculos de fecha complejos
Estado de la estandarización y perspectivas futuras
Temporal ya alcanzó la etapa 3 de la propuesta de ECMAScript (Stage 3), en la que se recomienda su implementación en navegadores
- Chrome y Firefox ya comenzaron a ofrecer soporte experimental, y se espera que otros navegadores también lo adopten
- Desde ahora, los desarrolladores pueden participar en la mejora de la especificación mediante pruebas y envío de retroalimentación
Date seguirá existiendo, pero todo apunta a que en el futuro Temporal será la forma predeterminada de manejar fechas
- El artículo cierra diciendo que “debió haberse reemplazado en 1995, pero incluso ahora,
Temporal.Now llega en el momento ideal”
1 comentarios
Comentarios en Hacker News
Este artículo trata varios comportamientos absurdos del constructor
Datede JavaScriptEn particular, explica el problema de que el formato
'YYYY-MM-DD'se interpreta como medianoche UTC, por lo que en la zona horaria local puede correrse un díaOriginalmente, en ISO 8601, si no se especifica una zona horaria debería asumirse la hora local, pero por un error al redactar la especificación de ES5 se trató como “Z” (UTC)
Después se intentó corregir en ES2015, pero como muchísimos sitios web dependían del comportamiento incorrecto anterior, se revirtió por compatibilidad web
Para más detalles, ver la sección Broken Parser
'strict datetime', al estilo de'use strict'Así se habría podido aplicar el comportamiento correcto de forma optativa, sin problemas de incompatibilidad con el código existente
O también podría haberse usado un enfoque como
import Date from 'browser:date', cargando un objeto global corregido desde un módulo internoNo tiene sentido que un valor que solo representa una fecha, como un cumpleaños, cambie por culpa de la zona horaria
Recuerdo que Outlook antes guardaba los cumpleaños con zona horaria incluida, así que cada vez que uno cambiaba de país el cumpleaños se movía un día
Pero, ¿había alguna alternativa? Forzar bifurcaciones por versión del navegador, como en la era de IE5, probablemente habría sido peor
Realmente envidio la forma de manejar el tiempo en Rails y Ruby
Una API como
Time.current.in_time_zone('America/Los_Angeles') + 3.days - 4.months + 1.houres intuitiva y poderosaRuby sobrecarga el objeto Time como un único objeto consistente, así que casi no hay que preocuparse por conversiones o casteos
En JS sería genial poder escribir algo tan simple como
new Date().add({ days: 1 })Además, también es debatible si sobrecargar la librería core es de verdad una buena aproximación
Es una lástima que Safari todavía no soporte la API Temporal
Ojalá la soporte el próximo año
JavaScript
Datetiene muchos problemas, pero no creo que el hecho de ser un objeto sea en sí el principalHabría sido mejor que fuera inmutable, pero no sorprende que un objeto mutable cambie
Dateque yo estaba usandoEl verdadero riesgo de la mutabilidad aparece en los cambios no locales, no en los locales
Es incómodo que la API Temporal no maneje en absoluto la información de segundos intercalares (
leap second)Quiero crear una herramienta de JS para cálculos astronómicos, pero para convertir a UTC hacen falta datos de segundos intercalares
Hay alternativas como
temporal-tai, pero tener que mantener el archivo de segundos intercalares del lado del cliente es muy engorrosoPor SOP (política CORS), tampoco se puede traer directamente el archivo desde un sitio externo
Los navegadores se actualizan periódicamente, así que resulta extraño que no incluyan esta información
Si el servidor configura el encabezado
Access-Control-Allow-Origino lo ofrece como archivo JS, sí se puedeAun así, que el navegador incluya y mantenga sus propios datos de segundos intercalares puede ser costoso
UTC, por definición, incluye segundos intercalares, así que en realidad sería más correcto decir que solo maneja tiempo POSIX
En el ejemplo de código, debería decir que desde
"50", y no"33", se interpreta como años de 1900; es solo una corrección de typoEstoy usando el polyfill de Temporal y hasta ahora me ha gustado mucho
En servidores o apps grandes está bien, pero para apps pequeñas puede ser una carga
Curiosamente, el artículo no menciona para nada
Date.now()Para compararlo con Temporal, debería haberlo usado como punto de referencia
Esta función devuelve el tiempo transcurrido en milisegundos desde el 1 de enero de 1970
Temporal tiene una API más amable, pero en el fondo su objetivo es representar la distancia relativa del tiempo
Entonces surge la duda de cómo convertirlos al formato deseado sin pasar por
DateSe deja una corrección pequeña pero importante: no es “daylight savings time”, sino “daylight saving time”
Hasta ahora no sabía que JS Date estuviera tan mal hecho
Si en ese momento hubieran sido un poco más cuidadosos, muchísimos desarrolladores no habrían caído en estas trampas