Skip to content

Methodology

Metodología de fecha y hora

Dónde falla la aritmética de fechas ingenua y cómo cada herramienta de /datetime/ la evita.

By Published

La aritmética de fechas y horas es una de las categorías de código más intentadas y con más errores en cualquier base de código grande. Las cuatro herramientas bajo nuestro clúster de Fecha y hora abordan cada una un subproblema diferente; esta página explica las matemáticas detrás de cada una.

Calculadora de edad: préstamo con conciencia del calendario

La edad en años-meses-días no es simplemente «hoy menos el cumpleaños dividido por 365.25»: esa aproximación acumula un día de error cada 4-7 años. El algoritmo correcto usa préstamo de calendario:

  1. Calcular la diferencia de años: ahora.año − nacimiento.año.
  2. Calcular la diferencia de meses. Si ahora.mes < nacimiento.mes, tomar prestados 12 meses del conteo de años.
  3. Calcular la diferencia de días. Si ahora.día < nacimiento.día, tomar días prestados del conteo de meses usando la longitud real del mes de calendario anterior.

El paso 3 es donde falla el código ingenuo. La «longitud del mes anterior» no es 30 o 31: depende de qué mes anterior (febrero tiene 28 o 29, el resto 30 o 31). Nuestra calculadora de edad usa new Date(año, mes, 0) (que devuelve el último día del mes anterior) para obtener el número correcto cada vez, incluidos los años bisiestos.

Ejemplo resuelto

Nacimiento: 1990-12-31. Hoy: 2026-05-14. Diferencia de años: 36. Diferencia de meses: −7 (mayo menos diciembre). Tomar prestado un año, la diferencia de meses pasa a 5. Diferencia de días: 14 − 31 = −17. Tomar prestado un mes; el mes anterior es abril con 30 días, así que sumar 30, dando una diferencia de días de 13. Resultado: 35 años, 4 meses, 13 días.

Diferencia de fechas: tres unidades, un denominador

La herramienta de diferencia de fechas reporta la diferencia entre dos fechas en días, semanas y horas simultáneamente. Las matemáticas son sencillas:

días = (b.getTime() − a.getTime()) / 86_400_000
semanas = días / 7 · horas = días × 24

La sutileza está en el manejo de zonas horarias. Ambas fechas se normalizan a medianoche UTC antes de la sustracción, por lo que las transiciones de horario de verano no introducen días fraccionarios. Una diferencia de fechas que abarca un cambio al horario de verano sigue siendo un número entero de días, como esperan los usuarios.

Días hábiles: de lunes a viernes entre dos fechas

El contador de días hábiles usa el algoritmo más simple posible: recorrer cada día de calendario entre las dos fechas e incrementar un contador cuando el día de la semana es de lunes a viernes.

Con ~250 días hábiles por año y una construcción de objeto Date que promedia ~1 µs en el V8 moderno, esto se completa en microsegundos para cualquier rango de fechas inferior a un siglo. No usamos una fórmula de forma cerrada porque es solo marginalmente más rápida y significativamente más difícil de leer.

Lo que no se incluye: festivos nacionales. La observancia de los festivos varía según el país, el año (la mayoría son de fecha fija pero un subconjunto significativo se mueve con el calendario lunar o se define como «el n-ésimo día de la semana del mes») y el sector. Necesitaríamos obtener datos de un conjunto de datos curado para hacerlo responsablemente; la herramienta de días hábiles se limita intencionalmente a días de la semana.

Conversor de zona horaria: IANA tzdata + Intl.DateTimeFormat

Las zonas horarias son construcciones políticas, no geográficas, y sus reglas cambian. Las fechas de inicio del horario de verano, los experimentos de horario de verano todo el año, las divisiones y fusiones a medida que los países se reorganizan: todo esto está capturado en el paquete tzdata de IANA que viene con todos los sistemas operativos modernos.

Nuestro conversor de zona horaria accede a esos datos a través del Intl.DateTimeFormat integrado en el navegador. Nunca incluimos nuestro propio tzdata. Esto importa porque:

  • tzdata se actualiza varias veces al año a medida que los países cambian las reglas.
  • Incluir nuestra propia copia congelaría esos datos en el momento de la compilación.
  • El tzdata a nivel del sistema operativo se actualiza por el proveedor del SO con una cadencia de seguridad más rápida que la nuestra.

El algoritmo de conversión de reloj de pared

Dada la pregunta «14:00 el 2026-07-04 en Europe/Istanbul, ¿qué hora es en America/Los_Angeles?»:

  1. Tratar «14:00 el 2026-07-04» como una marca de tiempo UTC (llamarla estimación).
  2. Preguntar a Intl.DateTimeFormat: en estimación, ¿qué offset tiene Europe/Istanbul? (UTC+3.)
  3. Ajustar: el instante UTC real es estimación − 3 horas.
  4. Representar ese instante UTC en el reloj de pared de Los_Angeles.

Esto maneja las zonas de media hora (India, UTC+5:30) y las zonas de 45 minutos (Nepal, UTC+5:45) sin casos especiales. El único caso que falla es la brecha del «avance de primavera»: las 2:30 AM no existen en una zona que salta de las 2:00 a las 3:00, pero la calculadora devuelve el resultado con una hora de diferencia en lugar de fallar, lo que sigue siendo información útil.

El valor predeterminado de ISO 8601

Todas las entradas de fecha en la interfaz de usuario usan el formato ISO 8601 (YYYY-MM-DD). Todos los objetos Date producidos internamente no tienen zona horaria en el límite y solo se vuelven conscientes de la zona horaria al cruzar al conversor de zona horaria. La salida de Intl.DateTimeFormat es consciente de la configuración regional en el idioma del navegador del usuario; los datos subyacentes siempre son ISO 8601 para el almacenamiento y la serialización.

Frequently asked questions

¿Por qué no usar una biblioteca de fechas como dayjs o date-fns?
Lo hacemos, internamente, para las partes que se benefician de ella, pero cada función visible en /lib/datetime/ está escrita desde primitivas. Las bibliotecas de fechas intercambian tamaño por conveniencia, y nuestras matemáticas son lo suficientemente simples (y estables) como para que la dependencia no valiera la pena.
¿El conversor de zona horaria gestiona fechas históricas?
Dentro del alcance de IANA tzdata, sí. IANA contiene reglas de transición de horario de verano que se remontan aproximadamente a 1970 para la mayoría de las zonas, y anteriores para un subconjunto. Para fechas anteriores a 1970, el offset devuelto es el offset moderno de la zona, que puede ser históricamente inexacto. No use el conversor de zona horaria para investigación genealógica.

Related

Published May 14, 2026