API Intl.DateTimeFormat

Formatea fechas y horas para cualquier localización sin bibliotecas externas

Introducción

Las fechas se muestran de manera diferente en todo el mundo. El 15 de enero de 2024 aparece como 1/15/2024 en Estados Unidos, 15/1/2024 en Reino Unido y 2024/1/15 en Japón. Los formatos de hora también varían. Los estadounidenses utilizan relojes de 12 horas con AM y PM, mientras que la mayor parte del mundo utiliza el formato de 24 horas.

Crear una lógica manual de formateo de fechas para diferentes locales es complejo y propenso a errores. Es necesario manejar el orden de días y meses, separadores, formatos de hora, conversiones de zona horaria y casos especiales como calendarios no gregorianos.

La API Intl.DateTimeFormat resuelve este problema. Proporciona un formateo de fecha y hora integrado y adaptado a cada locale en todos los navegadores modernos. No se requieren bibliotecas externas.

Uso básico

La forma más sencilla de formatear una fecha es crear una instancia de Intl.DateTimeFormat y llamar a su método format().

const date = new Date(2024, 0, 15, 14, 30);

const formatter = new Intl.DateTimeFormat("en-US");
formatter.format(date);
// "1/15/2024"

Cambia el locale para ver diferentes convenciones de formato.

const ukFormatter = new Intl.DateTimeFormat("en-GB");
ukFormatter.format(date);
// "15/01/2024"

const japanFormatter = new Intl.DateTimeFormat("ja-JP");
japanFormatter.format(date);
// "2024/1/15"

La misma fecha, formateada de tres maneras diferentes según las convenciones locales.

Entendiendo los locales

Un locale es una cadena que identifica un idioma y preferencias regionales. El formato sigue el estándar BCP 47: código de idioma, opcionalmente seguido por un código de región.

Patrones comunes de locale:

"en"      // Inglés (genérico)
"en-US"   // Inglés (Estados Unidos)
"en-GB"   // Inglés (Reino Unido)
"es"      // Español (genérico)
"es-MX"   // Español (México)
"es-ES"   // Español (España)
"zh-CN"   // Chino (China, Simplificado)
"zh-TW"   // Chino (Taiwán, Tradicional)

Si omites el parámetro de locale, el navegador utiliza el locale predeterminado del usuario.

const formatter = new Intl.DateTimeFormat();
formatter.format(date);
// El resultado varía según el locale del navegador del usuario

También puedes proporcionar un array de locales. El navegador utiliza el primer locale compatible.

const formatter = new Intl.DateTimeFormat(["es-MX", "es", "en"]);
// Usa Español (México) si está disponible, recurre al Español genérico, luego al Inglés

Resumen de opciones de formato

El constructor Intl.DateTimeFormat acepta un objeto de opciones que controla lo que aparece en la salida formateada. Hay dos enfoques para el formateo.

El primer enfoque utiliza atajos de estilo. Estos proporcionan un formateo rápido y convencional.

const formatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "full",
  timeStyle: "short"
});

formatter.format(date);
// "Monday, January 15, 2024 at 2:30 PM"

El segundo enfoque utiliza opciones de componentes. Estas dan un control granular sobre cada parte de la fecha.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric",
  hour: "numeric",
  minute: "numeric"
});

formatter.format(date);
// "January 15, 2024 at 2:30 PM"

No se pueden mezclar atajos de estilo con opciones de componentes. Elija un enfoque por formateador.

Atajos de estilo

Las opciones dateStyle y timeStyle proporcionan cuatro niveles preestablecidos de formato.

La opción dateStyle formatea la parte de la fecha.

const date = new Date(2024, 0, 15);

const full = new Intl.DateTimeFormat("en-US", { dateStyle: "full" });
full.format(date);
// "Monday, January 15, 2024"

const long = new Intl.DateTimeFormat("en-US", { dateStyle: "long" });
long.format(date);
// "January 15, 2024"

const medium = new Intl.DateTimeFormat("en-US", { dateStyle: "medium" });
medium.format(date);
// "Jan 15, 2024"

const short = new Intl.DateTimeFormat("en-US", { dateStyle: "short" });
short.format(date);
// "1/15/24"

La opción timeStyle formatea la parte del tiempo.

const date = new Date(2024, 0, 15, 14, 30, 45);

const full = new Intl.DateTimeFormat("en-US", { timeStyle: "full" });
full.format(date);
// "2:30:45 PM Eastern Standard Time"

const long = new Intl.DateTimeFormat("en-US", { timeStyle: "long" });
long.format(date);
// "2:30:45 PM EST"

const medium = new Intl.DateTimeFormat("en-US", { timeStyle: "medium" });
medium.format(date);
// "2:30:45 PM"

const short = new Intl.DateTimeFormat("en-US", { timeStyle: "short" });
short.format(date);
// "2:30 PM"

Combine ambas opciones para formatear fecha y hora juntas.

const formatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "medium",
  timeStyle: "short"
});

formatter.format(date);
// "Jan 15, 2024, 2:30 PM"

Los atajos de estilo se adaptan automáticamente a las convenciones de localización.

const usFormatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "short",
  timeStyle: "short"
});
usFormatter.format(date);
// "1/15/24, 2:30 PM"

const deFormatter = new Intl.DateTimeFormat("de-DE", {
  dateStyle: "short",
  timeStyle: "short"
});
deFormatter.format(date);
// "15.1.24, 14:30"

El formato alemán utiliza puntos como separadores, invierte el orden de día y mes, y muestra el tiempo en formato de 24 horas. El formato estadounidense utiliza barras, ordenamiento con el mes primero, y tiempo de 12 horas con AM/PM. Las mismas opciones, pero con salidas diferentes según la configuración regional.

Opciones de componentes

Las opciones de componentes proporcionan un control preciso sobre lo que se muestra y cómo. Cada opción especifica una parte de la fecha o la hora.

La opción year muestra el año.

const formatter = new Intl.DateTimeFormat("en-US", { year: "numeric" });
formatter.format(date);
// "2024"

const twoDigit = new Intl.DateTimeFormat("en-US", { year: "2-digit" });
twoDigit.format(date);
// "24"

La opción month muestra el mes en varios formatos.

const numeric = new Intl.DateTimeFormat("en-US", { month: "numeric" });
numeric.format(date);
// "1"

const twoDigit = new Intl.DateTimeFormat("en-US", { month: "2-digit" });
twoDigit.format(date);
// "01"

const long = new Intl.DateTimeFormat("en-US", { month: "long" });
long.format(date);
// "January"

const short = new Intl.DateTimeFormat("en-US", { month: "short" });
short.format(date);
// "Jan"

const narrow = new Intl.DateTimeFormat("en-US", { month: "narrow" });
narrow.format(date);
// "J"

La opción day muestra el día del mes.

const formatter = new Intl.DateTimeFormat("en-US", { day: "numeric" });
formatter.format(date);
// "15"

const twoDigit = new Intl.DateTimeFormat("en-US", { day: "2-digit" });
twoDigit.format(date);
// "15"

La opción weekday muestra el día de la semana.

const long = new Intl.DateTimeFormat("en-US", { weekday: "long" });
long.format(date);
// "Monday"

const short = new Intl.DateTimeFormat("en-US", { weekday: "short" });
short.format(date);
// "Mon"

const narrow = new Intl.DateTimeFormat("en-US", { weekday: "narrow" });
narrow.format(date);
// "M"

Combine múltiples opciones de componentes para crear formatos de fecha personalizados.

const formatter = new Intl.DateTimeFormat("en-US", {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric"
});

formatter.format(date);
// "Monday, January 15, 2024"

El navegador maneja los espacios y la puntuación según las convenciones de configuración regional.

Formato de hora

Las opciones del componente de tiempo controlan la visualización de horas, minutos y segundos.

const date = new Date(2024, 0, 15, 14, 30, 45);

const formatter = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  second: "numeric"
});

formatter.format(date);
// "2:30:45 PM"

La opción hour12 controla la visualización del tiempo en formato de 12 horas versus 24 horas.

const hour12 = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  hour12: true
});
hour12.format(date);
// "2:30 PM"

const hour24 = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  hour12: false
});
hour24.format(date);
// "14:30"

La opción hourCycle proporciona un control más preciso sobre la visualización de las horas. Existen cuatro opciones.

// h11: 0-11
const h11 = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  hourCycle: "h11"
});
h11.format(new Date(2024, 0, 15, 0, 30));
// "0:30 AM"

// h12: 1-12
const h12 = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  hourCycle: "h12"
});
h12.format(new Date(2024, 0, 15, 0, 30));
// "12:30 AM"

// h23: 0-23
const h23 = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  hourCycle: "h23"
});
h23.format(new Date(2024, 0, 15, 0, 30));
// "0:30"

// h24: 1-24
const h24 = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  hourCycle: "h24"
});
h24.format(new Date(2024, 0, 15, 0, 30));
// "24:30"

La diferencia importa a medianoche. El ciclo h11 usa 0, mientras que h12 usa 12. De manera similar, h23 usa 0, mientras que h24 usa 24.

La opción dayPeriod añade marcadores descriptivos de período para el formato de 12 horas.

const morning = new Date(2024, 0, 15, 10, 30);
const afternoon = new Date(2024, 0, 15, 14, 30);
const night = new Date(2024, 0, 15, 22, 30);

const formatter = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  dayPeriod: "long"
});

formatter.format(morning);
// "10:30 in the morning"

formatter.format(afternoon);
// "2:30 in the afternoon"

formatter.format(night);
// "10:30 at night"

La opción dayPeriod solo funciona con formatos de tiempo de 12 horas.

La opción fractionalSecondDigits muestra la precisión subsegundo.

const date = new Date(2024, 0, 15, 14, 30, 45, 123);

const oneDigit = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  second: "numeric",
  fractionalSecondDigits: 1
});
oneDigit.format(date);
// "2:30:45.1 PM"

const threeDigits = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  second: "numeric",
  fractionalSecondDigits: 3
});
threeDigits.format(date);
// "2:30:45.123 PM"

Puedes especificar uno, dos o tres dígitos fraccionarios.

Manejo de zonas horarias

La opción timeZone convierte fechas a zonas horarias específicas.

const date = new Date("2024-01-15T14:30:00Z"); // Hora UTC

const newYork = new Intl.DateTimeFormat("en-US", {
  timeZone: "America/New_York",
  dateStyle: "full",
  timeStyle: "long"
});
newYork.format(date);
// "Monday, January 15, 2024 at 9:30:00 AM EST"

const tokyo = new Intl.DateTimeFormat("ja-JP", {
  timeZone: "Asia/Tokyo",
  dateStyle: "full",
  timeStyle: "long"
});
tokyo.format(date);
// "2024年1月15日月曜日 23:30:00 日本標準時"

const london = new Intl.DateTimeFormat("en-GB", {
  timeZone: "Europe/London",
  dateStyle: "full",
  timeStyle: "long"
});
london.format(date);
// "Monday, 15 January 2024 at 14:30:00 GMT"

El mismo momento en el tiempo se muestra de manera diferente según la zona horaria. Utiliza identificadores de zona horaria IANA como America/New_York, Europe/London o Asia/Tokyo.

La opción timeZoneName muestra el nombre de la zona horaria.

const formatter = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  timeZone: "America/New_York",
  timeZoneName: "short"
});
formatter.format(date);
// "9:30 AM EST"

const long = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  timeZone: "America/New_York",
  timeZoneName: "long"
});
long.format(date);
// "9:30 AM Eastern Standard Time"

const shortOffset = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  timeZone: "America/New_York",
  timeZoneName: "shortOffset"
});
shortOffset.format(date);
// "9:30 AM GMT-5"

const longOffset = new Intl.DateTimeFormat("en-US", {
  hour: "numeric",
  minute: "numeric",
  timeZone: "America/New_York",
  timeZoneName: "longOffset"
});
longOffset.format(date);
// "9:30 AM GMT-05:00"

Diferentes valores de timeZoneName proporcionan diferentes niveles de detalle.

Sistemas de calendario y sistemas de numeración

La opción calendar admite calendarios no gregorianos.

const date = new Date(2024, 0, 15);

const gregorian = new Intl.DateTimeFormat("en-US", {
  calendar: "gregory",
  year: "numeric",
  month: "long",
  day: "numeric"
});
gregorian.format(date);
// "January 15, 2024"

const japanese = new Intl.DateTimeFormat("ja-JP", {
  calendar: "japanese",
  year: "numeric",
  month: "long",
  day: "numeric"
});
japanese.format(date);
// "令和6年1月15日"

const islamic = new Intl.DateTimeFormat("ar-SA", {
  calendar: "islamic",
  year: "numeric",
  month: "long",
  day: "numeric"
});
islamic.format(date);
// "٦ رجب ١٤٤٥"

const chinese = new Intl.DateTimeFormat("zh-CN", {
  calendar: "chinese",
  year: "numeric",
  month: "long",
  day: "numeric"
});
chinese.format(date);
// "2023甲辰年腊月初五"

La misma fecha se convierte a diferentes sistemas de calendario. Los calendarios disponibles incluyen gregory, japanese, islamic, islamic-umalqura, islamic-tbla, islamic-civil, islamic-rgsa, chinese, hebrew, indian, persian y otros.

La opción numberingSystem muestra dígitos en diferentes sistemas de escritura.

const date = new Date(2024, 0, 15);

const western = new Intl.DateTimeFormat("en-US", {
  numberingSystem: "latn",
  year: "numeric",
  month: "numeric",
  day: "numeric"
});
western.format(date);
// "1/15/2024"

const arabic = new Intl.DateTimeFormat("en-US", {
  numberingSystem: "arab",
  year: "numeric",
  month: "numeric",
  day: "numeric"
});
arabic.format(date);
// "١‏/١٥‏/٢٠٢٤"

const devanagari = new Intl.DateTimeFormat("en-US", {
  numberingSystem: "deva",
  year: "numeric",
  month: "numeric",
  day: "numeric"
});
devanagari.format(date);
// "१/१५/२०२४"

const bengali = new Intl.DateTimeFormat("en-US", {
  numberingSystem: "beng",
  year: "numeric",
  month: "numeric",
  day: "numeric"
});
bengali.format(date);
// "১/১৫/২০২৪"

Los sistemas de numeración disponibles incluyen latn (dígitos occidentales), arab (dígitos arábigo-índicos), arabext (dígitos arábigo-índicos extendidos), beng (dígitos bengalíes), deva (dígitos devanagari) y muchos otros.

Formateo de rangos de fechas

El método formatRange() formatea un rango de fechas con omisión inteligente de información redundante.

const start = new Date(2024, 0, 15);
const end = new Date(2024, 0, 20);

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

formatter.formatRange(start, end);
// "January 15 – 20, 2024"

El formateador omite información repetida. Ambas fechas están en enero de 2024, por lo que la salida solo incluye el mes y el año una vez.

Cuando el rango abarca diferentes meses, ambos se muestran.

const start = new Date(2024, 0, 15);
const end = new Date(2024, 1, 20);

formatter.formatRange(start, end);
// "January 15 – February 20, 2024"

Cuando el rango abarca diferentes años, se muestra toda la información.

const start = new Date(2024, 0, 15);
const end = new Date(2025, 1, 20);

formatter.formatRange(start, end);
// "January 15, 2024 – February 20, 2025"

El método formatRange() también funciona con rangos de tiempo.

const start = new Date(2024, 0, 15, 14, 30);
const end = new Date(2024, 0, 15, 16, 45);

const formatter = new Intl.DateTimeFormat("en-US", {
  month: "long",
  day: "numeric",
  hour: "numeric",
  minute: "numeric"
});

formatter.formatRange(start, end);
// "January 15, 2:30 – 4:45 PM"

La fecha se muestra una sola vez porque ambos horarios ocurren el mismo día.

Acceso a partes formateadas

El método formatToParts() devuelve un array de objetos que representan cada parte de la fecha formateada. Esto permite una lógica de formateo personalizada.

const date = new Date(2024, 0, 15, 14, 30);

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric",
  hour: "numeric",
  minute: "numeric"
});

const parts = formatter.formatToParts(date);

Cada objeto en el array tiene una propiedad type y value.

[
  { type: "month", value: "January" },
  { type: "literal", value: " " },
  { type: "day", value: "15" },
  { type: "literal", value: ", " },
  { type: "year", value: "2024" },
  { type: "literal", value: " at " },
  { type: "hour", value: "2" },
  { type: "literal", value: ":" },
  { type: "minute", value: "30" },
  { type: "literal", value: " " },
  { type: "dayPeriod", value: "PM" }
]

Puedes filtrar y manipular estas partes para construir formatos personalizados.

const dateParts = parts.filter(part =>
  ["month", "day", "year"].includes(part.type)
);

const dateString = dateParts.map(part => part.value).join("/");
// "January/15/2024"

El método formatRangeToParts() proporciona la misma funcionalidad para rangos de fechas.

const start = new Date(2024, 0, 15);
const end = new Date(2024, 0, 20);

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const parts = formatter.formatRangeToParts(start, end);

Cada objeto parte incluye una propiedad source que indica si proviene de la fecha de inicio o de fin.

[
  { type: "month", value: "January", source: "startRange" },
  { type: "literal", value: " ", source: "startRange" },
  { type: "day", value: "15", source: "startRange" },
  { type: "literal", value: " – ", source: "shared" },
  { type: "day", value: "20", source: "endRange" },
  { type: "literal", value: ", ", source: "shared" },
  { type: "year", value: "2024", source: "shared" }
]

Mejores prácticas

Reutiliza las instancias del formateador cuando formatees múltiples fechas con las mismas opciones. Crear un formateador implica negociación de localización y resolución de opciones, lo que tiene un pequeño coste de rendimiento.

// Menos eficiente
dates.forEach(date => {
  const formatted = new Intl.DateTimeFormat("en-US").format(date);
  console.log(formatted);
});

// Más eficiente
const formatter = new Intl.DateTimeFormat("en-US");
dates.forEach(date => {
  const formatted = formatter.format(date);
  console.log(formatted);
});

Utiliza la configuración regional del navegador del usuario cuando sea posible omitiendo el parámetro de localización. Esto respeta las preferencias del usuario.

const formatter = new Intl.DateTimeFormat();
// Usa la configuración regional del navegador automáticamente

Proporciona configuraciones regionales alternativas cuando te dirijas a regiones específicas. Si la configuración regional preferida no está disponible, el navegador utilizará la siguiente opción.

const formatter = new Intl.DateTimeFormat(["fr-CA", "fr", "en"]);
// Prefiere francés (Canadá), recurre al francés y luego al inglés

Utiliza atajos de estilo para visualizaciones comunes de fecha y hora. Se adaptan automáticamente a las convenciones de la configuración regional y requieren menos configuración.

const formatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "medium",
  timeStyle: "short"
});

Utiliza opciones de componentes cuando necesites un control preciso sobre el formato de salida.

const formatter = new Intl.DateTimeFormat("en-US", {
  weekday: "long",
  year: "numeric",
  month: "long",
  day: "numeric"
});

Especifica siempre la zona horaria cuando muestres horas a usuarios remotos o para eventos programados. Sin una zona horaria, las fechas se formatean en la zona horaria local del usuario, que puede no coincidir con tu intención.

const formatter = new Intl.DateTimeFormat("en-US", {
  timeZone: "America/New_York",
  dateStyle: "full",
  timeStyle: "long"
});

Utiliza formatRange() para rangos de fechas en lugar de formatear cada fecha por separado y concatenarlas. El método gestiona de forma inteligente la omisión de información redundante.

// Menos claro
const startFormatted = formatter.format(start);
const endFormatted = formatter.format(end);
const range = `${startFormatted} to ${endFormatted}`;

// Mejor
const range = formatter.formatRange(start, end);

Verifica la compatibilidad del navegador para funciones avanzadas como dayPeriod, fractionalSecondDigits y ciertos valores de timeZoneName. Todos los navegadores modernos admiten la funcionalidad principal, pero las opciones más nuevas pueden requerir alternativas para navegadores más antiguos.