El objeto Intl
de localización proporciona un interesante mecanismo llamado RelativeTimeFormat
que permite manejar y tratar fechas relativas en Javascript de forma nativa, sin necesidad de utilizar librerías externas, incluso añadiendo capacidad de diferentes idiomas.
Objeto | Descripción |
---|---|
Intl.RelativeTimeFormat | Crea un objeto de formato relativo con las preferencias de la región indicada. |
Una fecha relativa es el tiempo que se calcula respecto a otra fecha, habitualmente con textos como «Hace 10 minutos», «Hace 2 horas», «Dentro de 2 días», «Mañana», «Ayer», etc... Funciona de forma muy similar a Intl.DateTimeFormat, y podemos crear un objeto con una cierta configuración y luego utilizar los métodos .format()
o .formatToParts()
:
Método | Descripción |
---|---|
.format(value, unit) | Formatea valores en las unidades indicadas con la configuración regional. |
.formatToParts(value, unit) | Idem, pero devuelve un |
.resolvedOptions() | Devuelve las opciones de región definidas en la instancia. |
Ten en cuenta que podemos utilizar el método .resolvedOptions()
para obtener las opciones por defecto que se han utilizado al generar la instancia de la configuración de formato relativo.
El objeto RelativeTimeFormat
Comencemos viendo un ejemplo de RelativeTimeFormat
, donde formateamos varios valores teniendo en cuenta las diferentes unidades.
Vamos a utilizar el método .format()
de la instancia del objeto Intl.RelativeTimeFormat
con una ubicación de España. Esto hará que el texto se genere en el formato de esa región:
new Intl.RelativeTimeFormat("es-ES").format(1, "day"); // "dentro de 1 día"
new Intl.RelativeTimeFormat("es-ES").format(30, "minute"); // "dentro de 30 minutos"
new Intl.RelativeTimeFormat("es-ES").format(30, "minutes"); // "dentro de 30 minutos"
new Intl.RelativeTimeFormat("es-ES").format(-5, "month"); // "hace 5 meses"
new Intl.RelativeTimeFormat("es-ES").format(-1, "day"); // "hace 1 día"
Observa que en el segundo y tercer caso, estamos usando tanto
minute
comominutes
. Funciona para ambos, por lo que las unidades pueden indicarse tanto en singular como plural.
En el ejemplo anterior, hemos utilizado sólo el parámetro es-ES
para inicializar la instancia de RelativeTimeFormat
, pero es posible indicar un segundo parámetro de opciones para personalizar la configuración regional:
Opción | Descripción |
---|---|
localeMatcher | Indica el algoritmo para determinar la localización: lookup o best fit (por defecto). |
numeric | Indica si usa números: always (siempre, por defecto) o auto (usa otros si puede). |
style | Estilo del formato: long (por defecto), short , narrow . |
Por ejemplo, utilicemos el parámetro numeric
a auto
, para que en lugar de utilizar siempre el formato numérico pueda cambiarlo por otra frase o palabra cuando sea posible:
const rtf = new Intl.RelativeTimeFormat("es-ES", { numeric: "auto" });
rtf.format(1, "day"); // "mañana"
rtf.format(2, "day"); // "pasado mañana"
rtf.format(0, "day"); // "hoy"
rtf.format(-1, "day"); // "ayer"
rtf.format(-2, "day"); // "anteayer"
rtf.format(-1, "month"); // "el mes pasado"
rtf.format(1, "month"); // "el próximo mes"
Formatear fechas relativas
Ahora que sabemos como funciona, vamos a intentar aplicarlo a un ejemplo más parecido a la realidad, combinándolo con el objeto Date de Javascript. Imaginemos una situación en la que tenemos la fecha de un artículo, postDate
, y la fecha del día actual al cargar la página (imaginemos que estamos en el 10/Feb/2022).
Calculamos la diferencia entre ambas fechas (nos lo devuelve en milisegundos), por lo que dividimos para pasarlo a la unidad buscada, 1000
para los milisegundos, 60
para los segundos, 60
para los minutos y finalmente 24
para las horas. Nos quedamos con los días:
const postDate = new Date(2022, 0, 31); // 31/Ene/2022
const currentDate = new Date(); // Fecha actual: 10/Feb/2022
const time = Number.parseInt((postDate - currentDate) / 1000 / 60 / 60 / 24);
const rtf = new Intl.RelativeTimeFormat("es-ES", { numeric: "auto" })
const date = rtf.format(time, "day");
"hace 10 días"
Con este sistema en mente, no nos costaría mucho crear una función que haga las conversiones de fechas y con RelativeTimeFormat
te devuelva el texto con la localización que queramos (o indiquemos).
Igual que hemos trabajado con .format()
, podemos hacerlo con .formatToPart()
. La diferencia es que el primero nos devuelve un
const rtf = new Intl.RelativeTimeFormat("es-ES", { numeric: "auto" });
rtf.format(60, "hour");
// Devuelve un string
"dentro de 60 horas"
rtf.formatToParts(60, "hour");
// Devuelve un array de objetos
[
{ type: "literal", value: "dentro de " },
{ type: "literal", value: "60", unit: "hour" },
{ type: "literal", value: " horas" }
]
Esto hace que sea posible trabajar con estos datos para hacer personalizaciones posteriores, donde podríamos acceder o buscar campos especificos y quedarnos con los valores que necesitemos.