Date Utils — Referencia rápida
Utilidades mínimas para trabajar con fechas usando Intl, nativo del navegador y de Node. Tras configurar el alias @/* hacia src/*, importa desde @/lib/date.
No hace falta date-fns ni dayjs para lo básico: formatear, calcular diferencias, comparar días y generar secuencias de fechas (por ejemplo, para pintar un calendario).
Formatear
Sección titulada «Formatear»formatDate() — Formatear una fecha
Sección titulada «formatDate() — Formatear una fecha»Formatea una fecha con Intl.DateTimeFormat. Por defecto usa locale es y estilo medium, pero ambos son configurables por si necesitas otro formato puntual.
export function formatDate( date: Date, options: Intl.DateTimeFormatOptions = { dateStyle: "medium" }, locale = "es"): string { return new Intl.DateTimeFormat(locale, options).format(date)}import { formatDate } from "@/lib/date"
formatDate(new Date())// "15 ago 2026"
formatDate(new Date(), { dateStyle: "full" })// "sábado, 15 de agosto de 2026"formatTime() — Formatear una hora
Sección titulada «formatTime() — Formatear una hora»Igual que formatDate(), pero para la hora. Por defecto usa estilo short (sin segundos).
export function formatTime( date: Date, options: Intl.DateTimeFormatOptions = { timeStyle: "short" }, locale = "es"): string { return new Intl.DateTimeFormat(locale, options).format(date)}import { formatTime } from "@/lib/date"
formatTime(new Date())// "14:32"formatRelativeTime() — Tiempo relativo
Sección titulada «formatRelativeTime() — Tiempo relativo»Formatea la diferencia entre una fecha y ahora como texto relativo (“hace 3 días”, “en 2 horas”), eligiendo automáticamente la unidad más grande que tenga sentido con Intl.RelativeTimeFormat.
const RELATIVE_UNITS: { unit: Intl.RelativeTimeFormatUnit; ms: number }[] = [ { unit: "year", ms: 31536000000 }, { unit: "month", ms: 2592000000 }, { unit: "week", ms: 604800000 }, { unit: "day", ms: 86400000 }, { unit: "hour", ms: 3600000 }, { unit: "minute", ms: 60000 }, { unit: "second", ms: 1000 }]
export function formatRelativeTime(date: Date, locale = "es"): string { const diff = date.getTime() - Date.now() const formatter = new Intl.RelativeTimeFormat(locale, { numeric: "auto" })
for (const { unit, ms } of RELATIVE_UNITS) { if (Math.abs(diff) >= ms || unit === "second") { return formatter.format(Math.round(diff / ms), unit) } }
return formatter.format(0, "second")}import { formatRelativeTime } from "@/lib/date"
const haceTresDias = new Date(Date.now() - 3 * 86400000)formatRelativeTime(haceTresDias)// "hace 3 días"formatDateRange() — Formatear un rango
Sección titulada «formatDateRange() — Formatear un rango»Formatea dos fechas como un rango legible con Intl.DateTimeFormat.prototype.formatRange, que evita repetir el mes o el año cuando ambas fechas caen en el mismo período.
export function formatDateRange( start: Date, end: Date, options: Intl.DateTimeFormatOptions = { dateStyle: "medium" }, locale = "es"): string { return new Intl.DateTimeFormat(locale, options).formatRange(start, end)}import { formatDateRange } from "@/lib/date"
formatDateRange(new Date("2026-08-15"), new Date("2026-08-20"))// "15–20 ago 2026"Comparar y calcular
Sección titulada «Comparar y calcular»isSameDay() — Mismo día
Sección titulada «isSameDay() — Mismo día»Compara si dos fechas caen en el mismo día calendario (año, mes y día), ignorando la hora. Útil para resaltar “hoy” en un calendario o agrupar eventos por día.
export function isSameDay(a: Date, b: Date): boolean { return ( a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() )}import { isSameDay } from "@/lib/date"
const esHoy = isSameDay(evento.fecha, new Date())addDays() — Sumar días
Sección titulada «addDays() — Sumar días»Devuelve una nueva fecha desplazada por la cantidad de días indicada (negativa para restar). No muta la fecha original.
export function addDays(date: Date, amount: number): Date { const result = new Date(date) result.setDate(result.getDate() + amount) return result}import { addDays } from "@/lib/date"
const vencimiento = addDays(new Date(), 30)daysBetween() — Días entre dos fechas
Sección titulada «daysBetween() — Días entre dos fechas»Calcula la cantidad de días entre dos fechas, normalizando ambas a UTC antes de restar para evitar desfases por cambios de horario de verano.
export function daysBetween(a: Date, b: Date): number { const msPerDay = 86400000 const utcA = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()) const utcB = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()) return Math.round((utcB - utcA) / msPerDay)}import { daysBetween } from "@/lib/date"
const diasRestantes = daysBetween(new Date(), vencimiento)Rangos y secuencias
Sección titulada «Rangos y secuencias»startOfDay() — Inicio del día
Sección titulada «startOfDay() — Inicio del día»Devuelve una nueva fecha con la hora en 00:00:00.000, sin mutar la original. Base para comparar fechas ignorando la hora y para dateRange().
export function startOfDay(date: Date): Date { const result = new Date(date) result.setHours(0, 0, 0, 0) return result}import { startOfDay } from "@/lib/date"
const hoyDesdeCero = startOfDay(new Date())startOfMonth() / endOfMonth() — Límites del mes
Sección titulada «startOfMonth() / endOfMonth() — Límites del mes»Devuelven el primer y el último día del mes de la fecha dada, con la hora en cero. endOfMonth() aprovecha que el “día 0” de un mes en JS es el último día del mes anterior.
export function startOfMonth(date: Date): Date { return new Date(date.getFullYear(), date.getMonth(), 1)}
export function endOfMonth(date: Date): Date { return new Date(date.getFullYear(), date.getMonth() + 1, 0)}import { endOfMonth, startOfMonth } from "@/lib/date"
const inicio = startOfMonth(new Date())const fin = endOfMonth(new Date())dateRange() — Secuencia de fechas
Sección titulada «dateRange() — Secuencia de fechas»Genera un array de fechas entre start y end (ambos extremos incluidos), avanzando de a stepDays días. Reutiliza startOfDay() y addDays() de esta misma librería para no repetir la lógica de avanzar días.
export function dateRange(start: Date, end: Date, stepDays = 1): Date[] { const dates: Date[] = [] let current = startOfDay(start) const last = startOfDay(end)
while (current.getTime() <= last.getTime()) { dates.push(current) current = addDays(current, stepDays) }
return dates}import { dateRange } from "@/lib/date"
const semana = dateRange(new Date("2026-08-10"), new Date("2026-08-16"))// [10, 11, 12, 13, 14, 15, 16] de agostoeachDayOfMonth() — Todos los días del mes
Sección titulada «eachDayOfMonth() — Todos los días del mes»Devuelve un array con todas las fechas del mes de la fecha dada. Es dateRange() aplicado entre startOfMonth() y endOfMonth() — el caso típico para pintar una grilla de calendario.
export function eachDayOfMonth(date: Date): Date[] { return dateRange(startOfMonth(date), endOfMonth(date))}import { eachDayOfMonth } from "@/lib/date"
const diasDeAgosto = eachDayOfMonth(new Date("2026-08-01"))// 31 fechas, una por díaResumen
Sección titulada «Resumen»| Función | Qué hace |
|---|---|
formatDate() | Formatear una fecha con Intl.DateTimeFormat |
formatTime() | Formatear una hora |
formatRelativeTime() | Formatear una fecha como tiempo relativo (“hace 3 días”) |
formatDateRange() | Formatear un rango de dos fechas |
isSameDay() | Comparar si dos fechas son el mismo día calendario |
addDays() | Sumar (o restar) días a una fecha, sin mutar |
daysBetween() | Calcular días entre dos fechas, sin errores de DST |
startOfDay() | Fecha con la hora en cero |
startOfMonth() / endOfMonth() | Primer y último día del mes |
dateRange() | Generar un array de fechas entre dos extremos |
eachDayOfMonth() | Generar un array con todos los días del mes |
Consideraciones
Sección titulada «Consideraciones»Intl.RelativeTimeFormat,Intl.DateTimeFormatyformatRange()están disponibles en todos los navegadores modernos y en Node — no hace falta polyfill.daysBetween()normaliza a UTC antes de restar: compararDatedirectamente con horas incluidas puede dar resultados fuera por un día cuando cruza un cambio de horario.dateRange()incluye ambos extremos y no valida questartsea anterior aend— sistartes posterior, devuelve un array vacío en vez de contar hacia atrás.eachDayOfMonth()ydateRange()pueden devolver arrays grandes con rangos largos (años) — no pensadas para generar miles de fechas directamente sola vez.- Para fechas que llegan directamente de una API como texto, convierte primero con
new Date(valor)antes de pasarlas a estas funciones.