cover

Cómo aplicar formato de moneda y fecha en Javascript

author photo

David Zavala

@DeividZavala


robot logo saying hello

No te quedes atrás: Actualízate

Suscríbete para recibir información sobre nuevos frameworks, updates, eventos, tips, hacks y más.

Cuando trabajamos en una aplicación, en particular de lado de la UI, el cómo mostramos la información es un punto importante para que nuestra interfaz sea entendible, estética y, por supuesto, funcional. En muchos casos esta información es texto plano que basta con mostrar tal como lo tenemos, pero en otros casos trabajamos con valores númericos, booleanos o cadenas de texto (strings) que necesitamos mostrar con formatos específicos.

En esta ocasión quiero centrarme en 2 de los más comunes, fechas y valores que querramos mostrar como moneda (e.j. $10.00).

Para estos casos seguramente has pensado que lo mejor sea utilizar una librería tipo date-fns o momentJS para el formato de fechas y dinero.js para el formato de moneda, pero puede no ser la mejor idea, ¿a qué me refiero? en muchos casos simplemente necesitamos cambiar Thu Aug 04 2022 16:42:27 GMT-0500 (hora de verano central) por 04/08/2022 o agregar un $ al valor númerico 10.00, e instalar una librería para solo hacer esto parece excesivo, ¿no crees?.

Las alternativas

Clase Date

Date.toLocaleDateString

Lo más simple es utilizar el método toLocaleDateString que nos proporciona la clase Date

const date = new Date(2022,07,10) // Thu Aug 04 2022 16:42:27 GMT-0500 (hora de verano central) date.toLocaleDateString() // '10/8/2022'

Si buscas utilizar el formato de diferentes regiones del mundo (locale):

const date = new Date(2022,07,10) // Thu Aug 04 2022 16:42:27 GMT-0500 (hora de verano central) date.toLocaleDateString("en-US") // Inglés americano '8/10/2022' date.toLocaleDateString("en-GB") // Inglés británico '10/08/2022' date.toLocaleDateString("ru") // Ruso '10.08.2022' date.toLocaleDateString("ko") // Coreano '2022. 8. 10.'

Y también puedes cambiar el formato en que se muestra el día o mes por ejemplo:

const date = new Date(2022,07,10) // Thu Aug 04 2022 16:42:27 GMT-0500 (hora de verano central) const options = {weekday: "long", year: "numeric", month: 'long', day: 'numeric'} date.toLocaleDateString("en-US", options) // Inglés americano => 'Wednesday, August 10, 2022' date.toLocaleDateString("es-MX", options) // Español => miércoles, 10 de agosto de 2022' date.toLocaleDateString("ru", options) // Ruso => 'среда, 10 августа 2022 г.' date.toLocaleDateString("ko", options) // Coreano => '2022년 8월 10일 수요일'

Las keys más utilizadas que podemos agregar al objeto de options son:

  • weekday, valores posibles => "narrow", "short", "long"
  • era, valores posibles => "narrow", "short", "long"
  • year, valores posibles => "numeric", "2-digit"
  • month, valores posibles => "narrow", "short", "long", "numeric", "2-digit"
  • day, valores posibles => "numeric", "2-digit"
  • hour, valores posibles => "numeric", "2-digit"
  • minute, valores posibles => "numeric", "2-digit"
  • second, valores posibles => "numeric", "2-digit"
  • timeZoneName, valores posibles => "narrow", "short", "long"
  • hour12, selecciona si usar horario de 12 horas o 24 horas y depende del locale, valores posibles => "true", "false"

Hay otras opciones que podemos agregar que son menos comunes, si quieres explorarlas te comparto este artículo donde las puedes explorar.

Por último, este método nos permite añadir un locale de respaldo en caso de que el que hayamos solicitado no esté soportado:

// cuando se solicita un idioma que puede no estar soportado como el balinés, // incluir un idioma de reserva, en este caso el indonesio date.toLocaleDateString(["ban", "id"], options)

Muy útil, ¿no te parece?. Esta alternativa es perfecta para cuando las operaciones que necesitamos hacer con las fechas no son complicadas. Sin embargo, te quiero compartir otra alternativa, perfecta para casos donde necesitas un poco más de opciones para formatear las fechas y (aquí va la sorpresa) que también nos permite dar formato a listas de valores (arrays) y números (además de formato a fechas, claro), ¡Una verdadera maravilla de JavaScript!

Objeto Intl

El objeto Intl nos permite acceder a la API de internacionalización de ECMAScript, que proporciona comparación de cadenas sensible al idioma, formato de números y formato de fecha y hora. El objeto Intl proporciona acceso a varios métodos útiles para internacionalización y a otras funciones sensibles al lenguaje.

Intl.DateTimeFormat

Siguiendo la línea de formato de fechas, veamos cómo es que haríamos lo mismo que hicimos con Date, pero ahora con Intl:

const date = new Date(2022,07,10) // Thu Aug 04 2022 16:42:27 GMT-0500 (hora de verano central) new Intl.DateTimeFormat("en-US").format(date) // Inglés americano '8/10/2022' new Intl.DateTimeFormat("en-GB").format(date) // Inglés británico '10/08/2022' new Intl.DateTimeFormat("ru").format(date) // Ruso '10.08.2022' new Intl.DateTimeFormat("ko").format(date) // Koreano '2022. 8. 10.'

Al igual que con el método toLocaleDateString, podemos pasar un objeto de opciones para modificar el formato con que se muestran algunas secciones de la fecha:

const date = new Date(2022,07,10) // Thu Aug 04 2022 16:42:27 GMT-0500 (hora de verano central) const options = {weekday: "long", year: "numeric", month: 'long', day: 'numeric'} new Intl.DateTimeFormat("en-US", options).format(date) // Inglés americano => 'Wednesday, August 10, 2022' new Intl.DateTimeFormat("es-MX", options).format(date) // Español => miércoles, 10 de agosto de 2022' new Intl.DateTimeFormat("ru", options).format(date) // Ruso => 'среда, 10 августа 2022 г.' new Intl.DateTimeFormat("ko", options).format(date) // Koreano => '2022년 8월 10일 수요일'

Las keys que vimos previamente también aplican para DateTimeFormat. Sin embargo, tenemos la posibilidad de añadir algunas otras para configurar aún más cómo es que queremos mostrar nuestras fechas, te dejo la referencia para que las puedas revisar por aquí.

A este punto no hay mucha diferencia o una razón en particular para usar una forma o la otra, más allá de tu preferencia personal, si la implementación que buscas es tan simple como lo anterior, pero ahora te voy a mostrar un método de Intl que me parece increible.

Intl.RelativeTimeFormat

Si lo que necesitas es mostrar una fecha en formato relativo, es decir, algo como "dentro de 3 días" o "el año pasado", entonces este método es perfecto.

const relative = new Intl.RelativeTimeFormat("es") relative.format(5, "hour") // 'dentro de 5 horas' relative.format(5, "day") // 'dentro de 5 días' relative.format(-5, "hour") // 'hace 5 horas' relative.format(-5, "day") // 'hace 5 días' const relative = new Intl.RelativeTimeFormat("en-US") relative.format(5, "day") // 'in 5 days' relative.format(5, "hour") // 'in 5 hours' relative.format(-5, "day") // '5 days ago' relative.format(-5, "hour") // '5 hours ago'

Nota: Para expresar fechas pasadas, el valor que colocamos es negativo

Si lo que quieres es cambiar el formato del mensaje, puedes pasar un objeto de options.

const relative = new Intl.RelativeTimeFormat("es", {numeric: "auto", style: "long"}) relative.format(1, "day") // 'mañana' relative.format(-1, "day") // 'ayer' relative.format(1, "year") // 'el próximo año' relative.format(-1, "year") // 'el año pasado'

Puedes revisar el resto de las opciones posibles aquí.

Importante: Observa que este método no recibe un objeto de fecha, solo recibe un valor númerico y un identificador temporal (day o month) que sirve para el formato internacionalizado. El cálculo para sacar el valor númerico lo tenemos que hacer nosotros, pero no te preocupes, más adelante de digo cómo.

¡Basta de fechas!

Como te mencioné al principio de este artículo, el formato de moneda es otro de los que posiblemente ocupes más y que también veremos aquí y sí, Intl también nos cubre con esto.

Intl.NumberFormat

Este método permite formatear los números en función del idioma, siendo el formato de moneda al que le daremos prioridad, pero igual te comentaré un poco los demás, ya sabes, por no dejar.

El uso es simple y muy similar a lo que hemos visto hasta el momento.

const nfEs = new Intl.NumberFormat('es-ES'); const nfEn = new Intl.NumberFormat('en-EU'); const nfFr = new Intl.NumberFormat('fr'); nfEs.format(123456.78); // '123.456,78' nfEn.format(123456.78); // '123,456.78' nfFr.format(123456.78); // '123 456,78'

Genial, ¿no?, vamos a mejorarlo.

const nfEs = new Intl.NumberFormat('es-ES',{style: 'currency', currency: 'MXN'}); const nfEn = new Intl.NumberFormat('en-EU', {style: 'currency', currency: 'USD'}); const nfFr = new Intl.NumberFormat('fr', {style: 'currency', currency: 'EUR'}); nfEs.format(123456.78); // '123.456,78 MXN' nfEn.format(123456.78); // '$123,456.78' nfFr.format(123456.78); // '123 456,78 €'

Importante: En los ejemplos anteriores el primer valor (es-ES o en-US) corresponde al locale y es el que determina realmente cómo es que se mostrará nuestro valor por lo que aunque estemos mostrando pesos mexicanos (MXN) el formato en que se muestra puede variar segun el locale, veamos un ejemplo:

const nfEs = new Intl.NumberFormat('es-ES',{style: 'currency', currency: 'MXN'}); const nfMx = new Intl.NumberFormat('es-MX', {style: 'currency', currency: 'MXN'}); nfEs.format(123456.78) // '123.456,78 MXN' nfMx.format(123456.78) // '$123,456.78'

A pesar de que en los 2 casos estamos mostrando pesos mexicanos (MXN) indicado en la llave currency de las options, la forma en la que se muestra el valor es distinto debido a que los locales, son distintos, uno es formato europeo (es-ES o español de españa) y el otro es formato mexicano (es-MX).

Por último, hay otra propiedad de las options que podemos pasar que me parece interesante y que me gustaría compartirte, currencyDisplay.

new Intl.NumberFormat('es-MX', {style: 'currency', currency: 'MXN', currencyDisplay:"name"}).format(123456); // '123,456.00 pesos mexicanos' new Intl.NumberFormat('es-MX', {style: 'currency', currency: 'MXN', currencyDisplay:"symbol"}).format(123456); // '$123,456.00'

Puedes revisar el resto de las opciones posibles aquí.

Finalmente, quiero mencionar otras opciones que tiene NumberFormat, las unidades y los porcentajes

Unidades

new Intl.NumberFormat('es-MX', {style: 'unit', unit: 'kilometer-per-hour',unitDisplay: 'long'}).format(63); // '63 kilómetros por hora' new Intl.NumberFormat('es-MX', {style: 'unit', unit: 'kilometer-per-hour',unitDisplay: 'short'}).format(63); // '63 km/h' new Intl.NumberFormat('es-MX', {style: 'unit', unit: 'kilogram',unitDisplay: 'short'}).format(63); // '63 kg'

Puedes revisar el resto de las unidades posibles aquí.

Porcentaje

new Intl.NumberFormat('es-MX', {style: 'percent'}).format(0.63); // '63 %'

Bonus

Adicional a lo que hemos visto quiero platicarte de otros métodos que tiene Intl que también son interesantes:

Intl.ListFormat

Este método es en realidad muy simple, nos permite mostrar una lista legible de valores para cada idioma partiendo de una array de valores

const names = ["Mariana","David", "Bliss", "Brenda"] new Intl.ListFormat('es-ES').format(names) // 'Mariana, David, Bliss y Brenda' new Intl.ListFormat('en-US').format(names) // 'Mariana, David, Bliss and Brenda'

Puedes cambiar la forma en la que se muestra la lista agregando la llave type al objeto de options:

new Intl.ListFormat('es-ES', {type: "disjunction"}).format(names) // 'Mariana, David, Bliss o Brenda'

Los valores posibles son:

  • conjunction, para listas de tipo "y"
  • disjunction para listas de tipo "o"
  • unit si la lista es de unidades de medida, que se suelen poner en forma de lista de modo diferente.

Intl.PluralRules

Este método lo podemos describir como algo más avanzado y está pensado para ser una ayuda cuando necesitamos pluralizar valores o palabras, pero ojo, no funciona pasando una cadena y que nos devuelva el valor pluralizado, el funcionamiento es de más bajo nivel.

Por ejemplo, en español, inglés u otros idiomas occidentales una viga mide 1 metro (singular), 3 metros (plural) o, curiosamente, 0 metros (plural aunque sea cero). Sin embargo, en árabe tiene otras acepciones para ciertos números.

const prEs = new Intl.PluralRules('es-ES'); const prMa = new Intl.PluralRules('ar-MA'); // 'ESPAÑOL:'; prEs.select(0); // 'other' prEs.select(1); // 'one' prEs.select(3); // 'other' prEs.select(0.5); // 'other' // 'ÁRABE:'; prMa.select(0); // 'zero' prMa.select(1); // 'one' prMa.select(3); // 'few' prMa.select(0.5); // 'other'

Como puedes observar, para los idiomas occidentales generalmente hay dos posibilidades: 'one' (singular) o 'other' (plural), y con eso podemos decidir si se le pone una "s" al final o no, por ejemplo:

Si hablamos de pez (singular) y peces (plural), no es simplemente agregar una s. Sin embargo, para casos más simples puede ser de mucha ayuda.

Ahora sí, para terminar...

Si llegaste hasta aquí, agradezco que te hayas tomado el tiempo de leer este post y quiero cerrar con lo que prometí antes: un par de algoritmos que nos ayuden a completementar y sacar el mayor provecho de lo que acabamos de ver.

Cambiar el estilo de cómo mostramos la fecha

Si queremos cambiar el caracter con el que mostramos la fecha, directamente con estos métodos no es posible, pero si hacemos un poco de algoritmia podemos lograrlo:

function getFormattedDate(date){ const ye = new Intl.DateTimeFormat('es', { year: 'numeric' }).format(date); const mo = new Intl.DateTimeFormat('es', { month: 'short' }).format(date); const da = new Intl.DateTimeFormat('es', { day: '2-digit' }).format(date); return `${da}-${mo}-${ye}` } getFormattedDate(new Date(2022,07,10)) // '10-ago-2022'

Sacar los días entre 2 fechas para usarlos con RelativeTimeFormat

En realidad es muy simple ya que con JavaScript podes operar fechas de forma que podamos sacar como entero los días, años o meses entre 2 fechas.

Ejemplo con días:

function getRelativeDate(date1, date2){ const diffInMs = date2 - date1; const days = diffInMs / (1000 * 60 * 60 * 24); return new Intl.RelativeTimeFormat("es-MX", {numeric: "auto", style: "long"}).format(days, "day") } const d1 = new Date(2022,07,10) // '10-ago-2022' const d2 = new Date(2022,07,07) // '7-ago-2022' getRelativeDate(d1,d2) // 'hace 3 días' getRelativeDate(d2,d1) // 'dentro de 3 días'
course banner

¿Quieres mantenerte al día sobre los próximos cursos y eventos?

Suscríbete a nuestro newsletter

Jamás te enviaremos spam, nunca compartiremos tus datos y puedes cancelar tu suscripción en cualquier momento 😉

robot logo saying hello
facebook icontwitter iconlinkedin iconinstagram iconyoutube icon

© 2016 - 2023 Fixtergeek