Controlar fechas con JavaScript y DayJs

En este artículo veremos cómo controlar fechas con JavaScript y DayJs, la cómoda librería para validar, parsear y mostrar variables de tipo datetimes.

https://day.js.org/ “Fast 2kB alternative to Moment.js with the same modern API.”

See the Pen Controlar fechas con JavaScript y DayJs by Danivalldo (@Danivalldo) on CodePen.

¿Quieres aprender a hacer este ejercicio? Saltar directamente al tutorial

Podríamos preguntar a cualquier programador Javascript al azar, qué supone para él trabajar con fechas y “datetimes”. Y es probable que se echara a llorar. Para, a continuación, contárnos cómo de traumática fue la experiencia que vivió desarrollando un proyecto donde se requería de manejar fechas y horas entre países.

Bromas a parte, tener que lidiar con este tipo de variables, ha sido siempre un sinónimo de quebradero de cabeza.

Factores como los múltiples formatos existentes, los desfases horarios entre zonas del mundo o la localización entre países. Por nombrar algunos, son los responsables de que se convierta en algo tan complejo. Fireship lo resume de forma genial en este vídeo:

La herencia de MomentJs

El objetivo de la librería Dayjs, es el de simplificar todo eso, y la verdad es que lo resuelve de forma excelente.

Sin embargo, antes de empezar a analizar cómo trabaja su API, es importante destacar que ésta librería nació como alternativa a MomentJs. Otra librería orientada a parsear, validar y manipular fechas y horas en Javascript.

Durante mucho tiempo, MomentJs fue la opción más popular entre los desarrolladores. Especialmente cuando el ecosistema Javascript aún se encontraba en las versiones más tempranas del ECMAScript. Por aquél entonces los navegadores aún no soportaban muchas de las funcionalidades de hoy en día.

A pesar de eso, la evolución de estas tecnologías provocó que MomentJs dejara de ser considerada la opción más viable en términos de optimización. Y así lo especifican en su página oficial.

En consecuencia, se alentó el uso de otras librerías más modernas como Dayjs, creada por iamkun y su equipo. 

Con un diseño completamente basado en MomentJs. Dayjs consiguió que todos aquellos proyectos que ya usaban MomentJs, pudieran migrar a Dayjs. Pudiendo aprovechar su declarativa API, y sin tener que aprender una tecnología desde cero.

Tras visitar su página en Github, una de las características que precisamente llama más la atención es su reducido peso. De alrededor de 2kB. Muchas funcionalidades han sido encapsuladas en plugins externos, y deben ser importadas previamente para su uso.

En cuanto a su popularidad. A pesar de haber acumulado más de 3700 estrellas en el momento de escribir estas líneas, no supera las que MomentJs logró en su momento.

Empezemos a ver su API

Empezar a utilizar DayJs, es tan sencillo como ejecutar “npm install dayjs –save”. Tras unos pocos segundos de descarga, ya estará lista para importar en nuestro proyecto.

Su API se caracteriza por ser inmutable. Eso signifca que todos los métodos que modifican las propiedades del objeto Javascript, devuelven una instancia nueva en su lugar. De este modo, se previene la potencial aparición de “bugs” y a su vez, permite encadenar en una misma instrucción la ejecución de múltiples métodos.

Para obtener un objeto que contenga toda la información relativa a un ”datetime”, hay que ejecutar directamente la librería.

Al hacerlo, puede recibir como argumento la fecha de inicio en forma de cadena de texto, con el formato ISO 8601. O si se ejecuta sin pasar ningún parámetro, devolverá automáticamente un objeto que describe el instante actual.

Con el objeto devuelto, se puede obtener y/o setear varios valores. Como el dia de la semana, el año, el mes, o incluso, los minutos, segundos y hasta milisegundos. Todo mediante métodos como “.day()”, “.year()” o “.hour()”.

Pero donde realmente brilla esta librería, es con los métodos de manipulación. Algunos como “.add()” o “.subtract()”, permiten añadir o restar cualquier fracción de tiempo con una sintaxis que casi parece inglés.

Finalmente podemos pedir a DayJs que devuelva un “output” formateado convenientemente, gracias a su método “format”. Ese método admite como argumento una cadena de texto con la estructura de “output” deseada.

Aunque la web oficial no muestra ejemplos, es sencillo hacerse una idea de las posibilidades prácticas que ofrece esta herramienta. Sin ir más lejos, programar una webapp que ofrezca las horas actualizadas de distintos países, sería pan comido con esta librería.

E incluso se me ocurre la posibilidad de mostrar esa información directamente sobre un mapa. Combinando DayJs, y a la librería OpenLayers, que ya vimos en su momento.

Un vistazo a todas las opciones de DayJs

Como ejercicio, para ver en marcha DayJs, vamos a exponer el resultado de algunos de los métodos y propiedades del objeto creado por la librería.

Para ello vamos a empezar creando un sencillo formulario con un solo campo de tipo datetime-local. Este va a permitir al usuario seleccionar una fecha deseada.

A continuación vemos cómo implementar la primera parte del layout HTML para que contenga dicho selector.

<div>
 <h1>Selecciona una fecha</h1>
 <input type="datetime-local" class="date-time__selector" />
</div>

La segunda parte de la estructura, va a agrupar un conjunto de botones para manipular la fecha seleccionada de distintas formas.

    <div class="actions-container">
      <div>
        <button class="btn btn-action" data-action="add" data-time-type="second" >Añadir un segudo</button>
        <button class="btn btn-action" data-action="add" data-time-type="minute" >Añadir un minuto</button>
        <button class="btn btn-action" data-action="add" data-time-type="hour" >Añadir una hora</button>
        <button class="btn btn-action" data-action="add" data-time-type="day" >Añadir un dia</button>
        <button class="btn btn-action" data-action="add" data-time-type="month" >Añadir un mes</button>
        <button class="btn btn-action" data-action="add" data-time-type="year" >Añadir un año</button>
      </div>
      <div>
        <button class="btn btn-action" data-action="subtract" data-time-type="second" >Restar un segudo</button>
        <button class="btn btn-action" data-action="subtract" data-time-type="minute" >Restar un minuto</button>
        <button class="btn btn-action" data-action="subtract" data-time-type="hour" >Restar una hora</button>
        <button class="btn btn-action" data-action="subtract" data-time-type="day" >Restar un dia</button>
        <button class="btn btn-action" data-action="subtract" data-time-type="month" >Restar un mes</button>
        <button class="btn btn-action" data-action="subtract" data-time-type="year" >Restar un año</button>
      </div>
      <div>
        <button class="btn btn-action" data-action="reset" data-time-type="second">Resetear segudos</button>
        <button class="btn btn-action" data-action="reset" data-time-type="minute">Resetear minutos</button>
        <button class="btn btn-action" data-action="reset" data-time-type="hour">Resetear hora</button>
        <button class="btn btn-action" data-action="reset" data-time-type="day">Resetear dia</button>
        <button class="btn btn-action" data-action="reset" data-time-type="month">Resetear mes</button>
        <button class="btn btn-action" data-action="reset" data-time-type="year">Resetear año</button>
      </div>
    </div>

Finalmente, añadiremos un conjunto de contenedores para mostrar el resultado en algunos de los formatos disponibles.

    <div>
      <h2>
        Resultado formateado
        <span>(DD-MM-YYYY HH:mm:ss)</span>
      </h2>
      <div class="formatted-result-container"></div>
    </div>
    <div>
      <h2>Resultado JSON</h2>
      <div class="json-result-container"></div>
    </div>
    <div>
      <h2>Resultado UNIX</h2>
      <div class="unix-result-container"></div>
    </div>

Con el objetivo de hacer una interfaz un poco más amigable, añadiremos los siguientes estilos CSS.

@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;700&display=swap");
body {
  margin: 0;
  padding: 0;
  text-align: center;
  font-family: "Open Sans", sans-serif;
  background-color: rgb(183, 238, 255);
  color: rgb(10, 47, 58);
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  box-sizing: border-box;
}
input {
  margin-bottom: 40px;
}
.btn {
  background-color: rgb(31, 91, 109);
  color: #fff;
  padding: 10px 15px 10px 15px;
  border-radius: 3px;
  border: none;
  margin-bottom: 5px;
}
h2 > span {
  display: block;
  font-size: 0.8rem;
}

Controlar las variables y fechas con JavaScript

Como último paso, vamos a programar el comportamiento deseado mediante Javascript y la librería DayJs.

Empezaremos el script, importando los estilos y la librería. 

import "./SCSS/index.scss";
import dayjs from "dayjs";

Seguidamente guardamos en variables referencias a los contenedores y selector del DOM.

const datetimeSelector = document.querySelector(".date-time__selector");
const actionsContainer = document.querySelector(".actions-container");
const resultFormattedContainer = document.querySelector(
  ".formatted-result-container"
);
const resultJSONContainer = document.querySelector(".json-result-container");
const resultUNIXContainer = document.querySelector(".unix-result-container");

Guardamos el instante actual en una variable de tipo let llamada “date”, y declaramos las siguientes funciones.

let date = dayjs();

La función “performAction” va a recibir “action” y “timeType”, para decidir con qué método va a actualizar la variable “date”.

const performAction = (action, timeType) => {
  switch (action) {
    case "reset":
      date = date.startOf(timeType);
      break;
    case "subtract":
      date = date.subtract(1, timeType);
      break;
    case "add":
    default:
      date = date.add(1, timeType);
      break;
  }
};

“handleOnChangeSelector“ se va a encargar de detectar si el usuario ha seleccionado una nueva fecha en el ”input”. Si el formato seleccionado es válido, llamará a la función “updateDisplay”, encargada de mostrar los resultados en pantalla.

const handleOnChangeSelector = (event) => {
  date = dayjs(event ? event.target.value : undefined);
  if (!date.isValid()) {
    return;
  }
  updateDisplay();
};
const updateDisplay = () => {
  datetimeSelector.value = date.format("YYYY-MM-DDTHH:mm:ss.SSS");
  resultFormattedContainer.innerHTML = date.format("DD-MM-YYYY HH:mm:ss");
  resultJSONContainer.innerHTML = date.toJSON();
  resultUNIXContainer.innerHTML = date.unix();
};

Como último paso, asignamos los “listeners” de eventos, y ejecutamos inmediatamente “handleOnChangeSelector”.

actionsContainer.addEventListener("click", (event) => {
  const element = event.target;
  if (!element.classList.contains("btn-action")) {
    return;
  }
  const action = element.dataset.action;
  const timeType = element.dataset.timeType;
  performAction(action, timeType);
  updateDisplay();
});
datetimeSelector.addEventListener("change", handleOnChangeSelector);
handleOnChangeSelector();

Imprescindible para cualquier proyecto JavaScript con fechas

A día de hoy no concibo la manera de controlar fechas con JavaScript, sin previamente haber importado DayJs. Se ha convertido en una herramienta imprescindible, como en su día fue MomentJs.

A pesar de que existen otras librerías que cubren las mismas funcionalidades, personalmente he incorporado DayJs a mi biblioteca de recursos.

Tal y como ya dijimos de TinyColor, se tratan de microlibrerias que resuelven mucho con muy poco.

Este ha sido un pequeño vistazo a la librería DayJs. A continuación os dejo enlaces a más recursos, así como el ejercicio subido al repositorio de Github de “Librerías Js”.

Nos vemos pronto, un abrazo desarrolladores!

Deja un comentario