Regreso al futuro
ProgramaciónCálculos con fechas
Marty McFly y Doc están a punto de probar su Delorean para viajar en el tiempo. De momento han implementado dos visores: uno con la fecha de destino y otra con la fecha actual.
El caso es que han pensado que les gustaría saber cuántos años, días, horas y minutos viajarían al pasado o al futuro a partir de los datos que metieran en el formulario. El mismo Marty se plantó ayer en nuestra casa con su monopatín volador para contarnos lo que necesitaban. El asunto viene a ser algo así:
Tenemos los dos visores de las fechas destino y presente y sus valores pueden introducirse libremente por el usuario en cada uno de los campos.
Necesitamos que, al pulsar el botón de cálculo de viaje nos diga si vamos a viajar al futuro o al pasado, y cuántos años, días, minutos y segundos vamos a desplazarnos.
Ejemplo de entrada:
En los campos de presente: OCT 26 1985 01:21
En los campos de destino: JUN 01 2020 17:00
Ejemplo de salida: Vas a viajar al futuro 34 años, 227 días, 14 horas y 39 minutos.
Nota: no necesitamos los meses porque pueden tener 28, 30 o 31 días.
Nos han facilitado el código del formulario para que no tengamos que preocuparnos de hacerlo nosotros. Tiene alguna validación sencilla en HTML5 y consideramos que no se van a meter datos erróneos. Los nombres de los meses contienen las tres primeras letras en español (ENE, FEB, MAR…).
Código fuente del formulario
[restrict]
[/restrict]
¡Recuerda que puedes trabajar con fechas mediante el objeto Date, que almacena los milisegundos que pasan desde el 1 de enero de 1970 hasta la fecha elegida!
Tweet
Y, para no variar, Edu nos planteó alguna cuestión…
Si los meses van con letra, necesitarás algún tipo de estructura para guardarlos, ¿no? Si las fechas se almacenan en milisegundos, ¿has pensado cómo harás para transformarlos a otras unidades de tiempo? ¿Te has dado cuenta que el resultado varía si viajas al futuro o al pasado? Por cierto, ¿sabes si estará el monopatín de Marty en AliExpress?
Resignación… escuché las preguntas, anoté alguna cosa que se me ocurrió y le dije: “No sé si el patinete estará, pero la chaqueta fijo”.
¿Tú cómo lo harías? ¡Deja tus ideas en los comentarios!
Y si quieres compartir código, te recomiendo que utilices alguna herramienta online de testing de código como Codepen, JSFiddle, PlayCode, etc. o repositorios como GitHub, GitLab, BitBucket…
Guillermo says
Me llevo un poco mal con las fechas pero esta es la solución que he podido sacar.
$(document).ready(function () {
$(“#calcular”).click(function () {
var MesPresente = $(“#presenteMes”).val();
var MesPresenteN;
var DiaPresente = $(“#presenteDia”).val();
var AnoPresente = $(“#presenteAno”).val();
var HoraPresente = $(“#presenteHora”).val();
var MinPresente = $(“#presenteMinuto”).val();
var MesDestino = $(“#destinoMes”).val();
var MesDestinoN;
var DiaDestino = $(“#destinoDia”).val();
var AnoDestino = $(“#destinoAno”).val();
var HoraDestino = $(“#destinoHora”).val();
var MinDestino = $(“#destinoMinuto”).val();
switch (MesPresente){
case “ENE”:
MesPresenteN = 0;
break;
case “FEB”:
MesPresenteN = 1;
break;
case “MAR”:
MesPresenteN = 2;
break;
case “ABR”:
MesPresenteN = 3;
break;
case “MAY”:
MesPresenteN = 4;
break;
case “JUN”:
MesPresenteN = 5;
break;
case “JUL”:
MesPresenteN = 6;
break;
case “AGO”:
MesPresenteN = 7;
break;
case “SEP”:
MesPresenteN = 8;
break;
case “OCT”:
MesPresenteN = 9;
break;
case “NOV”:
MesPresenteN = 10;
break;
case “DIC”:
MesPresenteN = 11;
break;
}
switch (MesDestino) {
case “ENE”:
MesDestinoN = 0;
break;
case “FEB”:
MesDestinoN = 1;
break;
case “MAR”:
MesDestinoN = 2;
break;
case “ABR”:
MesDestinoN = 3;
break;
case “MAY”:
MesDestinoN = 4;
break;
case “JUN”:
MesDestinoN = 5;
break;
case “JUL”:
MesDestinoN = 6;
break;
case “AGO”:
MesDestinoN = 7;
break;
case “SEP”:
MesDestinoN = 8;
break;
case “OCT”:
MesDestinoN = 9;
break;
case “NOV”:
MesDestinoN = 10;
break;
case “DIC”:
MesDestinoN = 11;
break;
}
var fechaPresente = new Date(AnoPresente, MesPresenteN, DiaPresente, HoraPresente, MinPresente, 0);
var fechaDestino = new Date(AnoDestino, MesDestinoN, DiaDestino, HoraDestino, MinDestino, 0);
var diferencia = fechaPresente – fechaDestino;
var mensaje = “”;
var anosaux=0;
var anos = diferencia / (1000 * 3600 * 24 * 365);
if (anos -1) {
anosaux = 0;
} else {
anosaux = anos
}
} else {
if (anos < 1) {
anosaux = 0;
} else {
anosaux = anos
}
}
var dias = (anos – Math.round(anosaux)) * 365;
var horas = (dias – Math.round(dias)) * 24;
var minutos = (horas – Math.round(horas)) * 60;
if (diferencia < 0) {
mensaje = mensaje + "ha viajado al futuro " + Math.abs(Math.round(anos)) + " años " + Math.abs(Math.round(dias)) + " dias " + Math.abs(Math.round(horas)) + " horas y " + Math.abs(Math.round(minutos))+" minutos.";
} else {
mensaje = mensaje + "ha viajado al pasado " + Math.abs(Math.round(anos)) + " años " + Math.abs(Math.round(dias)) + " dias " + Math.abs(Math.round(horas)) + " horas y " + Math.abs(Math.round(minutos)) + " minutos.";
}
$("#mensaje").text(mensaje);
})
});
Ada Lovecode says
¡Jejeje, creo que el odio a las fechas es generalizado, Guillermo!
Veo muy bien tu propuesta (¿sabrías hacer sin JQuery?) 🙂
Eso sí, el switch yo le daría una vuelta y optaría por algo más sencillito: ¿qué tal un array constante con los meses, y hacer búsquedas internas para saber cuál es la posición de cada mes? 😉 Además, fíjate que haces LO MISMO en los dos switches: eso se podría reducir a una sola función. Cuando repetimos código, lo ideal es modularizar.
El resto se parece bastante a mi solución… y hasta aquí puedo leer. ¡Gracias por tu propuesta, Guillermo!
José Julio says
El código no se ha subido bien. Faltan unas pocas líneas. Lástima que no se vea el texto formateado. Eso tienes que corregirlo. Cositas que aparecen con el rodaje de un nuevo sitio web. También hay que corregir en este caso en mí código los años bisiestos que también se incluyen en los milisegundos. Un dolor de cabeza esto de las fechas.
FEDERICO MACÍAS says
Muchas gracias, Ada, por los comentarios al código. Parece que me pasa con frecuencia eso de asociar el evento al click cuando tiene que ser a la carga del DOM.
¿Cómo sé cuando asociar una función a la carga del DOM y cuando al click del botón? ¿Qué me recomiendas para trabajar en ello??
Lo de las variables con el $ es una cosa que hago para variables que hacen referencia a elementos del DOM, aunque sí es verdad que es muy propio de PHP. No me gusta mucho el lenguaje PHP para el backend prefiero Nodejs, aunque para ello tengo que mejorar mucho en JavaScript del lado del cliente.
Muchas gracias , Ada.
Sigo trabajando en el cronómetro para Forrest, obviamente para variar, sigo teniendo dificultades en el código JavaScript con el innerHTML.
José Julio says
Este ha sido entretenido. ¿Puede haber un error en el enunciado? La fecha JUN 01 2020 17:00 creo que debería ser JUN 01 2000 17:00. Con la última fecha las horas que me salen a mí son 14 y no 15. Este es mi código:
window.addEventListener(“load”, inicio, false);
function inicio(){
document.getElementById(“calcular”).addEventListener(“click”,calcular,false);
}
function calcular(){
const milisegundos_en_un_anio = 31536000000;
const milisegundos_en_un_dia = 86400000;
const milisegundos_en_una_hora = 3600000;
const milisegundos_en_un_minuto = 60000;
meses = {“ENE”:”JAN”,”FEB”:”FEB”,”MAR”:”MAR”,”ABR”:”APR”,
“MAY”:”MAY”,”JUN”:”JUN”,”JUL”:”JUL”,”AGO”:”AUG”,
“SEP”:”SEP”,”OCT”:”OCT”,”NOV”:”NOV”,”DIC”:”DEC”}
// creo la cadena con la fecha del presente
let presente = meses[document.getElementById(“presenteMes”).value];
presente += ” ” + document.getElementById(“presenteDia”).value;
presente += ” ” + document.getElementById(“presenteAno”).value;
presente += ” ” + document.getElementById(“presenteHora”).value;
presente += “:” + document.getElementById(“presenteMinuto”).value;
// creo la cadena con la fecha destino
let destino = meses[document.getElementById(“destinoMes”).value];
console.log(destino);
destino += ” ” + document.getElementById(“destinoDia”).value;
destino += ” ” + document.getElementById(“destinoAno”).value;
destino += ” ” + document.getElementById(“destinoHora”).value;
destino += “:” + document.getElementById(“destinoMinuto”).value;
// creo los objetos fecha1 y fecha2 (presente y destino)
let fecha1 = new Date(presente);
let fecha2 = new Date(destino);
// calculo milisegundos entre las fechas
let milisegundos_totales = fecha2-fecha1;
// los milisegundos entre las dos fechas divididos por los
// milisegundos en un año son los años
let anios = Math.trunc(milisegundos_totales / milisegundos_en_un_anio);
// resto a los milisegundos totales los milisegundos de los años
milisegundos_totales -= Math.trunc(anios) * milisegundos_en_un_anio;
// los milisegundos que quedan divididos por los milisegundos
// en un día son los días
let dias = Math.trunc(milisegundos_totales / milisegundos_en_un_dia);
// resto a los milisegundos totales los milisegundos de los días
milisegundos_totales -= Math.trunc(dias) * milisegundos_en_un_dia;
// los milisegundos que quedan divididos por los milisegundos en
// una hora son las horas
let horas = Math.trunc(milisegundos_totales / milisegundos_en_una_hora);
// resto a los milisegundos totales los milisegundos de las horas
milisegundos_totales -= Math.trunc(horas) * milisegundos_en_una_hora;
// los milisegundos que quedan divididos por los milisegundos en
// un minuto son los minutos
let minutos = Math.trunc(milisegundos_totales / milisegundos_en_un_minuto);
// almaceno todo en un array para pasarla como argumento
let tiempo_transcurrido = [anios, dias, horas, minutos];
// si la fecha presente es anterior al destino
if((fecha1-fecha2) 0){
mensaje(“Viajas hacia el pasado “, tiempo_transcurrido, -1);
}
// si las fechas son iguales
else{
mensaje(“¿Se te ha parado el reloj? “, tiempo_transcurrido, 0);
}
}
function mensaje(texto_final, tiempo_transcurrido, numero){
// si numero es -1 significa que hemos viajado
// al pasado y convertimos en positivos los valores negativos
// para presentarlos por pantalla. Si numero es 1 quedan como están.
// Si numero es 0 no nos hemos movido
for(let x = 0; x<tiempo_transcurrido.length; x++){
tiempo_transcurrido[x] *= numero;
}
texto_final += tiempo_transcurrido[0] + " años " +
tiempo_transcurrido[1] + " días " +
tiempo_transcurrido[2] + " horas y " +
tiempo_transcurrido[3] + " minutos.";
alert(texto_final);
}
José Julio says
window.addEventListener(“load”, inicio, false);
function inicio(){
document.getElementById(“calcular”).addEventListener(“click”,calcular,false);
}
function calcular(){
const milisegundos_en_un_anio = 31536000000;
const milisegundos_en_un_dia = 86400000;
const milisegundos_en_una_hora = 3600000;
const milisegundos_en_un_minuto = 60000;
meses = {“ENE”:”JAN”,”FEB”:”FEB”,”MAR”:”MAR”,”ABR”:”APR”,
“MAY”:”MAY”,”JUN”:”JUN”,”JUL”:”JUL”,”AGO”:”AUG”,
“SEP”:”SEP”,”OCT”:”OCT”,”NOV”:”NOV”,”DIC”:”DEC”}
// creo la cadena con la fecha del presente
let presente = meses[document.getElementById(“presenteMes”).value];
presente += ” ” + document.getElementById(“presenteDia”).value;
presente += ” ” + document.getElementById(“presenteAno”).value;
presente += ” ” + document.getElementById(“presenteHora”).value;
presente += “:” + document.getElementById(“presenteMinuto”).value;
// creo la cadena con la fecha destino
let destino = meses[document.getElementById(“destinoMes”).value];
destino += ” ” + document.getElementById(“destinoDia”).value;
destino += ” ” + document.getElementById(“destinoAno”).value;
destino += ” ” + document.getElementById(“destinoHora”).value;
destino += “:” + document.getElementById(“destinoMinuto”).value;
// creo los objetos fecha1 y fecha2 (presente y destino)
let fecha1 = new Date(presente);
let fecha2 = new Date(destino);
// calculo milisegundos entre las fechas
let milisegundos_totales = fecha2-fecha1;
// los milisegundos entre las dos fechas divididos por los
// milisegundos en un año son los años
let anios = Math.trunc(milisegundos_totales / milisegundos_en_un_anio);
// resto a los milisegundos totales los milisegundos de los años
milisegundos_totales -= Math.trunc(anios) * milisegundos_en_un_anio;
// los milisegundos que quedan divididos por los milisegundos
// en un día son los días
let dias = Math.trunc(milisegundos_totales / milisegundos_en_un_dia);
// resto a los milisegundos totales los milisegundos de los días
milisegundos_totales -= Math.trunc(dias) * milisegundos_en_un_dia;
// los milisegundos que quedan divididos por los milisegundos en
// una hora son las horas
let horas = Math.trunc(milisegundos_totales / milisegundos_en_una_hora);
// resto a los milisegundos totales los milisegundos de las horas
milisegundos_totales -= Math.trunc(horas) * milisegundos_en_una_hora;
// los milisegundos que quedan divididos por los milisegundos en
// un minuto son los minutos
let minutos = Math.trunc(milisegundos_totales / milisegundos_en_un_minuto);
// almaceno todo en un array para pasarla como argumento
let tiempo_transcurrido = [anios, dias, horas, minutos];
// si la fecha presente es anterior al destino
if((fecha1-fecha2) 0){
mensaje(“Viajas hacia el pasado “, tiempo_transcurrido, -1);
}
// si las fechas son iguales
else{
mensaje(“¿Se te ha parado el reloj? “, tiempo_transcurrido, 0);
}
}
function mensaje(texto_final, tiempo_transcurrido, numero){
// si numero es -1 significa que hemos viajado
// al pasado y convertimos en positivos los valores negativos
// para presentarlos por pantalla. Si numero es 1 quedan como están.
// Si numero es 0 no nos hemos movido
for(let x = 0; x<tiempo_transcurrido.length; x++){
tiempo_transcurrido[x] *= numero;
}
texto_final += tiempo_transcurrido[0] + " años " +
tiempo_transcurrido[1] + " días " +
tiempo_transcurrido[2] + " horas y " +
tiempo_transcurrido[3] + " minutos.";
alert(texto_final);
}
José Julio says
Después de
// si la fecha presente es posterior a destino
else if((fecha1-fecha2)>0){
mensaje(“Viajas hacia el pasado “, tiempo_transcurrido, -1);
}
va este código:
// si la fecha presente es anterior al destino
if((fecha1-fecha2) > 0){
mensaje(«Viajas hacia el pasado «, tiempo_transcurrido, -1);
}
No lo ha subido bien.
Ada Lovecode says
¡Tomo nota, José Julio! De hecho, estoy trabajando en una segunda versión de la web… quizá este tipo de cosas las pueda solucionar… ¡ya lo irás viendo! ¡Un saludo y mil gracias!
Ada Lovecode says
¡¡Ole!! ¡Me alegro mucho, Guillermo! En este caso puedes hacerlo porque el índice del array coincide con el valor que necesitas. En otras ocasiones no te quedará más remedio que hacerlo con un switch… O CON UN OBJETO (clave:valor) o un ARRAY BIDIMENSIONAL.
En cualquier caso, nunca te acostarás… 😉
Ada Lovecode says
¡Buena idea, José Julio! Mi idea va por ahí también. Creo que no necesitas utilizar los dos valores de los meses porque con el español valdría 😉
Y un aporte: creo que se ve más claro, en lugar de poner los milisegundos en un número, poner las operaciones que has llevado a cabo para hacer el cálculo: así no hay posibilidad de error (o si la hay, lo ves más facil).
¡En nada os traigo la solución!
FEDERICO MACÍAS says
Hola, Ada. En primer lugar nuevamente decir que me encantan los retos que plateas y tus cursos de JavaScript. Muchas gracias por permitirme presentarte mi código. He de decir que este reto en especial le tenía muchas ganas porque me gusta mucho trabajar con fechas en vanilla JS pero, como comenté en Youtube, me salió un error a la hora de aplicarle el listener al botón. Me tomé la libertad de hacer un codepen provisional para este ejercicio, en el cual sólo anoté el código JS. El HTML es era el mismo que nos proporcionaste y el CSS… digamos que ofortunadamente es un curso de JavaScript y no de CSS, pero bueno… Dejo el link de enlace para el código. https://codepen.io/Scipio14/pen/JjGGKgJ
Muchas gracias por tomarte el tiempo para echarle un vistazo a mi código.
Espero ansioso la solución al reto y ya trabajando en el planteamiento del reto de Forrest Gump.
Muchas gracias por toda tu dedicación.
Federico