JavaScript Temporal está por llegar
(developer.mozilla.org)- El nuevo objeto Temporal de JavaScript está empezando a llegar a versiones experimentales de navegadores; es un cambio que busca manejar fechas, horas, duraciones y calendarios de forma más precisa y consistente mediante una API integrada
- El
Dateexistente dificultaba el manejo de zonas horarias y la depuración por su estructura centrada en la hora local del usuario y UTC, su parsing poco confiable y su comportamiento mutable - Temporal separa instantes, hora local y duraciones con
Temporal.Instant,Temporal.ZonedDateTime,Temporal.PlainDateTime,Temporal.Duration,Temporal.Now, entre otros, y ofrece más de 200 métodos utilitarios - Aún hará falta más tiempo para contar con soporte estable entre navegadores; en Firefox Nightly se puede probar Temporal detrás de la configuración
javascript.options.experimental.temporal - Esta semana se agregaron a MDN más de 270 páginas de documentación sobre Temporal, y en la página de documentación de TC39 que incluye
@js-temporal/polyfillse pueden ejecutar ejemplos sin cambiar flags
Las antiguas limitaciones de Date en JavaScript
- Cuando JavaScript se creó en 1995, el objeto
Datecopió la implementación inicial dejava.util.Datede Java; Java la reemplazó en 1997, pero JavaScript mantuvo casi la misma API durante casi 30 años - Los problemas más grandes son la falta de soporte de zonas horarias y el comportamiento de parsing poco confiable
- Solo soporta la hora local del usuario y UTC
- Como
Dateen sí es mutable, puede crear bugs difíciles de rastrear - También es difícil manejar cálculos que cruzan Daylight Saving Time (DST) y cambios históricos de calendario
- Debido a estas limitaciones, muchos desarrolladores han dependido de librerías dedicadas como Moment.js o date-fns para el manejo de fechas y horas en sus aplicaciones
Cómo Temporal cambia el modelo de fecha y hora
- Temporal fue diseñado como un reemplazo completo del objeto
Date, con el objetivo de hacer que la gestión de fechas y horas sea más confiable y predecible - Soporta representaciones de zonas horarias y calendarios, y ofrece métodos integrados para conversión, comparación, cálculo y formateo
- La superficie de la API incluye más de 200 métodos utilitarios, y la documentación de Temporal en MDN ya suma explicaciones y ejemplos
Tipos principales de Temporal
- Temporal distingue entre un instante único, la hora de reloj local y una duración mediante tipos diferentes
- Sus estructuras principales son las siguientes
Temporal.Duration: diferencia entre dos instantesTemporal.Instant: instante único expresado como timestampTemporal.ZonedDateTime: fecha y hora con zona horaria incluidaTemporal.PlainDateTime: fecha y hora completas sin zona horariaTemporal.PlainDate: representa solo la fechaTemporal.PlainYearMonth: año y mesTemporal.PlainMonthDay: mes y díaTemporal.PlainTime: representa solo la hora
Temporal.Now: API para obtener la hora actual como instancias de distintas clases o en formatos específicos
Uso con ejemplos
- Se puede obtener la fecha y hora actuales como una cadena ISO, y pasar una zona horaria a varios métodos
Temporal.Now.plainDateTimeISO()devuelve la fecha y hora actuales en la zona horaria del sistemaTemporal.Now.plainDateTimeISO("America/New_York")devuelve la fecha y hora actuales en la zona horaria de New York
- También se pueden manejar calendarios distintos del gregoriano, lo que permite crear fechas de sistemas de calendario como Hebrew, Chinese e Islamic
- Calcula el próximo Chinese New Year usando el día 1 de
M01del calendario Chinese - En la salida de ejemplo al momento de redactar, el próximo Chinese New Year es
1/29/2025
- Calcula el próximo Chinese New Year usando el día 1 de
- Un timestamp Unix Epoch en milisegundos se puede convertir en un instante con
Temporal.Instant.fromEpochMilliseconds()y comparar conTemporal.Now.instant()para calcular el tiempo restante- Para el timestamp de ejemplo
1851222399924, calcula el tiempo desde ahora consmallestUnit: "hour" - La salida de
@js-temporal/polyfilles31,600 hr, y la de Firefox Nightly esPT31600H
- Para el timestamp de ejemplo
- El
toLocaleStringde la implementación de Firefox actualmente no imprime una cadena sensible al locale- Este comportamiento se acerca más a una decisión de diseño que a una limitación técnica, y el formateo de duraciones en sí es posible
- El polyfill y la implementación de Firefox podrían converger más adelante
- El método
compare()se puede usar para ordenar arreglos- Al usar
durations.sort(Temporal.Duration.compare), se ordenan comoPT1H,PT1H30M,PT1H45M,PT2H
- Al usar
Soporte en navegadores y cómo probarlo
- El soporte de Temporal empezó a incorporarse lentamente en versiones experimentales de navegadores, y actualmente la implementación de Firefox parece ser la más madura
- En Firefox, Temporal se está compilando en la versión Nightly detrás de la configuración
javascript.options.experimental.temporal - Los principales issues de navegadores para seguir la implementación son los siguientes
- Firefox: Build temporal in Nightly by default
- Safari: [JSC] Implement Temporal
- Chrome: Implement the Temporal proposal
- El estado completo de compatibilidad se puede consultar en la sección Temporal object Browser Compatibility de MDN
- La documentación de TC39 sobre Temporal incluye
@js-temporal/polyfill, por lo que se pueden ejecutar ejemplos en la consola de herramientas de desarrollo de cualquier navegador sin cambiar flags ni configuraciones
1 comentarios
Comentarios en Hacker News
Temporal es excelente. Lo he usado en producción durante un tiempo con el polyfill, y resuelve muchos de los problemas que tenía con la API tradicional de
Date()Se siente como una muy buena combinación, con una API cómoda de usar, inspirada en buenas librerías de manejo de tiempo como
chronode Rust y Joda Time de JavaSepara el tiempo simple, los instantes y el tiempo con zona horaria, así que es un poco más complejo, pero el tiempo en sí ya es complejo, así que los desarrolladores tienen que enfrentar esa complejidad
Incluso en operaciones como “sumarle un día a este timestamp”, necesariamente hay que decidir si eso se hace según una zona horaria específica; si no, quedan bugs por horario de verano, cambios de zona horaria del usuario o diferencias de zona horaria del servidor
También resuelve la diferencia de serialización entre un timestamp con offset fijo (
2025-01-01T00:00+02:00) y una zona horaria específica (Europe/Paris)chrono: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...Personalmente, no creo que Temporal haya estado muy inspirado por
chronode Rust; parece tener mucha más influencia de Joda, del modernojava.time, y de librerías de fecha y hora de JavaScript como date-fns o Moment.jsNo quieren ponerse a averiguar si
Europe/Parissignifica una región amplia de Francia o solo París, y les molesta porque sienten que es como decir que viven en ParísEsto fue doloroso al programar cosas como eventos de comunidades en línea. La gente quiere usar offsets fijos, y expresiones como
CET/CESTles parecen bien, pero cosas comoEurope/yourexactcoordinatesno les gustanEn la práctica saben que la mayoría de las zonas horarias cubren regiones bastante amplias, pero hay mucha gente a la que le preocupa la privacidad y aun así no piensa investigar la diferencia entre “hora” y “zona horaria”
chronoy Joda Time son productos de épocas distintas. Cuando salió Rust 1.0, Java ya había implementado este enfoque con java.time en la biblioteca estándar, y no hacía falta una librería de terceros para este propósitoMe tomó bastante tiempo encontrarlo en la documentación, pero Temporal.ZonedDateTime.prototype.withTimeZone() convierte de una zona horaria a otra: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Si tomas un valor creado con
Temporal.ZonedDateTime.from("2021-08-01T12:00[America/New_York]")y lo pasas awithTimeZone("Europe/Paris"), se convierte en2021-08-01T18:00:00+02:00[Europe/Paris]La conversión de zona horaria y el manejo de períodos son funciones clave que una librería sí o sí debe cubrir, y está bien que Temporal se encargue de ambas. Eso sí, no parece que
Temporal.Durationtenga una funciónformatpersonalizada para producir algo como1h03m, por ejemploduration.format('H\hmm\m')1 yr,3 hours,3m: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...Antes implementé parte de eso en la librería icu4x
En TC39 hay varias propuestas que ya van madurando, y Temporal es una de las que ojalá salga pronto.
Como sé que para que los principales navegadores soporten nuevas funciones hace falta el trabajo de ingeniería de la gente de v8, JSC y SpiderMonkey, de verdad agradezco a quienes están impulsando el progreso.
Desde la impaciencia, uno termina alentando con algo como: “¡Saquen también Records y Tuples de una vez! ¡Incluso pueden saltarse la guerra de sintaxis de Pipe!”
Entiendo que los fabricantes de navegadores ya se oponen con bastante fuerza a agregar nuevos tipos primitivos en este punto. Las dificultades de cómo debería funcionar la igualdad están explicadas en este hilo: https://github.com/tc39/proposal-record-tuple/issues/387
Al principio no esperaba que BigInt se usara tanto de esta manera, pero en la práctica siguen apareciendo casos donde hacen falta colecciones con igualdad estructural, así que da pena.
Tengo entendido que la oposición a añadir nuevos tipos primitivos también afecta al pattern matching, pero no sé bien por qué y sigo menos esa propuesta.
Pipeline, pattern matching y Records+Tuples llevan más de 4 años en desarrollo y todavía siguen en etapa 1 o 2. En el último año casi no parece haber habido avances significativos, salvo quizá en pattern matching.
Según los issues del repositorio de Records y Tuples, hubo rechazo a la semántica de valor, es decir, a si
===puede funcionar. Si se quita la semántica de valor, la utilidad de la propuesta baja muchísimo.Para que lleguen a etapa 3 probablemente falten por lo menos 1 o 2 años más, o quizá nunca lleguen. Aun así, por lo menos ya tenemos las funciones de agrupación de arrays.
Lamentablemente todavía está en etapa 1, así que parece que faltan varios años más.
El Dictionary de AS3 era un tipo donde se podían usar referencias a objetos, cadenas y números como claves únicas, y asociarles valores de cualquier tipo. El recolector de basura también lo manejaba para que no fueran referencias débiles mientras el propio objeto diccionario siguiera vivo.
Era como pensar en el Set de JavaScript, pero con cualquier tipo de clave especificado, fuertemente tipado, y lanzando errores en tiempo de compilación. Extraño ese lenguaje.
Esas actualizaciones, en la práctica, arruinaron el ecosistema de JavaScript, y ahora da la impresión de que solo quedan lenguajes que compilan a JS. Quien todavía usa JS vainilla parece alguien construyendo una app en ensamblador.
Me pregunto cómo se mantiene actualizada la información de cada zona horaria dentro de Temporal.
¿La estructura es que TC39 actualiza los datos en algún lado y luego cada navegador copia internamente esos datos y saca una nueva versión? ¿Y si el usuario no actualizó a un navegador con los datos nuevos, entonces en mi sitio web verá horas incorrectas?
Por ejemplo, México eliminó el horario de verano en 2022: https://en.wikipedia.org/wiki/Time_in_Mexico
En librerías de terceros como
pytzomoment-timezone, basta con actualizar la librería del lado del servidor; y si lo maneja la biblioteca estándar, basta con subir la versión del lenguaje, pero no sé cómo funciona con Temporal y el navegador del visitante.Parece probable que la computadora del usuario también pueda acceder a esa base de datos y encargarse de las actualizaciones, pero no estoy seguro. También podría ser que el navegador descargue y mantenga esa base de datos por su cuenta; supongo que dependerá de la implementación.
Base de datos relacionada: https://en.wikipedia.org/wiki/Tz_database
Intl, así que si investigas por ese lado probablemente encuentres una respuesta parecida.tzdb.En general, sí parece correcto decir que si el usuario no actualiza el navegador o el sistema para reflejar los nuevos datos de zonas horarias, podría ver horas incorrectas. Pero esto no sería muy distinto de la práctica común actual.
La alternativa sería que cada aplicación trajera su propia
tzdb, y algunas apps hacen eso y a veces está justificado. Pero en general es un desperdicio, aumenta las inconsistencias entre aplicaciones y además es probable que haga más lento el ciclo de actualizaciones.Habría que agregar un evento para detectar cuando alguien cambie de zona horaria
A la lista de “mentiras que los programadores creen sobre el tiempo” también se podría sumar “los programadores creen que la zona horaria en uso es fija”. En la realidad, millones de personas cambian de zona horaria todos los días
Aunque claro, podría ser útil para las librerías
Es una gran lástima que
.Nowno sea una llamada de función. No debería ser una propiedadSi evalúas
.Nowvarias veces dentro de un bucle, podrías obtener un valor distinto cada vez, y eso no es lo esperableC# tomó la misma decisión y no debería haberlo hecho: https://ericlippert.com/2014/05/19/when-should-i-write-a-pro...
Nowes un namespace para funciones que obtienen valores reales; por ejemplo,Now.instant()La propuesta de Temporal realmente me gusta, pero hay una cosa que me molesta. En las comparaciones depende de la igualdad por referencia
Es decir,
Temporal.Instant.from('2020-01-01') != Temporal.Instant.from('2020-01-01')No es inherentemente malo, pero prácticamente elimina la posibilidad de usar estos objetos como claves de
Mapo juntarlos en unSet. Entiendo por qué se tomó esa decisión, pero igual da pena que no sea posibleQuizá algún día, si Records y Tuples llegan a existir de verdad, aparezca una versión basada en eso
==?.epochMillisecondscomo clave o elemento enMap/Set. Claro, si necesitas conservar datos de zona horaria en elMapo hacer operaciones adicionales deInstant, entonces tendrías que guardar elInstantoriginal en el valorEn el caso de
Set, podrías usar algo comoMap{v.epochMilliseconds:v}para conservar elInstantNo es ideal, pero esto es más culpa de JavaScript en sí que de Temporal. Podrían hacer que el runtime lo manejara, pero entonces el polyfill fallaría
Map/Setes parecido a usar números de punto flotante enMap/Set, y por lo general es una mala ideaString()o'2020-01-01'?Proveer una función de comparación que funcione junto con las APIs existentes es un diseño sólido. Hasta podría tomarse como requisito obligatorio al agregar nuevos tipos
Por ejemplo, si pasas
Temporal.Duration.compareasort, puedes ordenar en el ordenPT1H,PT1H30M,PT1H45M,PT2H. Aplausos para los diseñadoresEntiendo que el nombre
Temporalbusca evitar choques con objetos de tiempo más genéricos como Moment o Datetime, pero el nombre no me gustaLa primera vez que lo vi pensé que era algo como control del recolector de basura
temporalpuede significar algo relativo al tiempo en contraste con la eternidad, algo relacionado con los tiempos gramaticales o la distinción temporal, o algo relativo al tiempo en contraste con el espacio: https://www.merriam-webster.com/dictionary/temporalMe suena a un nombre razonable
Para empezar,
Temporalno es un sustantivo sino un adjetivo. Tiene relación con el tiempo, pero no encaja de forma intuitivaMás importante aún, elegir nombres raros para reducir la probabilidad de chocar con código viejo hace que, con el tiempo, el lenguaje se vuelva más opaco
Cuando se agregaron
PromiseyGenerator, también había muchas librerías que usaban esos nombres de objetos. A diferencia de las palabras reservadas, los objetos integrados se pueden sobrescribir, así que no era un gran problemaCreo que el comité de estándares debería haberse mantenido firme y usar
Timepor la salud a largo plazo del lenguajeClaro, esa discusión ya pasó y seguramente los fabricantes de navegadores y quienes implementan motores de JS ya se pusieron de acuerdo
DateV2Entiendo que se necesita compatibilidad hacia atrás, pero
Temporalsuena mal.DateTimeni siquiera es un nombre del estándar de JS, así que no sé por qué no usaron ese. Hasta entonces, probablemente dejeconst DateTime = TemporalArtículos relacionados:
JavaScript Temporal Is Coming - https://news.ycombinator.com/item?id=42809834 - enero de 2025, 18 comentarios
Mozilla: Temporal (Limited Availability) - https://news.ycombinator.com/item?id=42776548 - enero de 2025, 1 comentario
Is It Time for the JavaScript Temporal API? - https://news.ycombinator.com/item?id=29712118 - diciembre de 2021, 100 comentarios
Temporal: Getting started with JavaScript's new date time API - https://news.ycombinator.com/item?id=27661667 - junio de 2021, 194 comentarios
JavaScript Temporal - https://news.ycombinator.com/item?id=27395236 - junio de 2021, 1 comentario
JavaScript Proposal Temporal for Dates is now stage 3 - https://news.ycombinator.com/item?id=26432346 - marzo de 2021, 1 comentario
Le queda perfecto eso de que los barcos grandes tardan en cambiar de rumbo