Calendar showing the difference between two dates

Asked

Viewed 119 times

3

I want to make a difference calculator between dates. One that can make a difference in days, hours, etc.

Example: Initial - 07/17/2019 for Final - 07/29/2020. How long (in days) is the starting date for the final date? And how many hours?

I have the following code:

    //CALCULAR DIAS

        function CalcDias(){
                var data1 = new Date(document.getElementById("data1").value);
                var data2 = new Date(document.getElementById("data2").value);
                return parseInt((data1 - data2) / (24 * 3600 * 1000));
        }

    //CALCULAR HORAS

        function CalcHoras(){
                var data1 = new Date(document.getElementById("data1").value);
                var data2 = new Date(document.getElementById("data2").value);
                return parseInt((data1 - data2) / (24 * 3600 * 1000));
        }

    //CALCULAR SEGUNDOS

       function CalcSegundos(){
                var data1 = new Date(document.getElementById("data1").value);
               var data2 = new Date(document.getElementById("data2").value);
                return parseInt((data1 - data2) / (24 * 3600 * 1000));
        }

    //MOSTRAR RESULTADOS

        function result(){
        if(document.getElementById("data1")){
            document.getElementById("result_dias").value=CalcDias();
            document.getElementById("result_horas").value=CalcHoras();
            document.getElementById("result_segundos").value=CalcSegundos();

        }  
    }
<body>
    <div id="reserve_form">

    <div id="pickup_date"><p><label class="form">Primeira data:</label><input type="date" class="textbox" id="data2" name="data_2" onchange="result()"/></p></div>

    <div id="dropoff_date"><p><label class="form">Segunda data:</label><input type="date" class="textbox" id="data1" name="data_1" onchange="result()"/></p></div>

    <div id="numdays"><label class="form">Diferença em Dias:</label><input type="text" class="textbox" id="result_dias" name="dias"/></div>
    <br/>
    </div>
</body>

I just put the values "hours and seconds" to demonstrate how I want, but only the amount of days works.

There would be a way to perform a code similar to that of days to HOURS/SECONDS/MONTHS/YEARS?

  • Hi @Danna. I saw that Voce is a new user here, I recommend you see the following links before: Tour Stackoverflow and Help Stackoverflow, because in these links, they explain the environment here and also how to ask questions in Stack Overflow. Because here we do not create code and deliver to the people who ask and yes we help with doubts in codes of the people who ask the questions.

  • Oh yes, forgive me. I couldn’t explain very well! I even have a code set up, would it be a problem if I edited the question and showed my code? so I could ask for help in an easier way.

  • See the concept of Julian day and then just make a difference. That’s how most software does.

2 answers

2


How you’re using fields input type="date", means that they only have the day, month and year without any information about the time. So I don’t see how to calculate the difference in hours, unless that you assume that a difference of X days is the equivalent of X * 24 hours (and in this case, we are considered to be comparing the same time of the two days).

Anyway, the value of a input type="date" is always returned as a string in the "yyyy-mm-dd format" (also known as format ISO 8601). And when you create one Date passing a string in this format, it is interpreted as being that date at midnight in UTC. That is, the dates created are at the same time.

And when you subtract two instances of Date, the result is the difference between them, in milliseconds. As in this case the two dates have the same time (and still refers to the UTC, that does not have anomalies such as daylight saving time, which could interfere with the results), it is safe to assume that this difference value is multiple of 24 hours.

So to calculate the difference in seconds, just divide this value by 1000. To get the difference in minutes, divide by (1000 * 60), and so on:

// diferença em milissegundos
function diffMs(data1, data2) {
    return data2 - data1;
}

// diferença em segundos
function diffSecs(data1, data2) {
    return diffMs(data1, data2) / 1000;
}

// diferença em minutos
function diffMins(data1, data2) {
    return diffSecs(data1, data2) / 60;
}

// diferença em horas
function diffHoras(data1, data2) {
    return diffMins(data1, data2) / 60;
}

// diferença em dias
function diffDias(data1, data2) {
    return diffHoras(data1, data2) / 24;
}


function calcula(sel) {
    let data1 = document.getElementById('data1').value;
    let data2 = document.getElementById('data2').value;
    if (data1 && data2) { // se os 2 campos estão preenchidos
        let op = sel.options[sel.selectedIndex];
        let d1 = new Date(data1);
        let d2 = new Date(data2);
        let diff;
        switch (op.value) {
            case 'ms':
                diff = diffMs(d1, d2);
                break;
            case 's':
                diff = diffSecs(d1, d2);
                break;
            case 'm':
                diff = diffMins(d1, d2);
                break;
            case 'h':
                diff = diffHoras(d1, d2);
                break;
            case 'd':
                diff = diffDias(d1, d2);
                break;
        }
        if (diff !== undefined) {
            document.getElementById('resultado').innerHTML = `${diff} ${op.text}`;
        }         
    }
}
<form>
  <p><label class="form">Primeira data:</label><input type="date" class="textbox" id="data1" name="data1" /></p>
  <p><label class="form">Segunda data:</label><input type="date" class="textbox" id="data2" name="data2" /></p>
  <p>Escolha o cálculo:
    <select onchange="calcula(this)">
      <option value="">escolha</option>
      <option value="ms">milissegundos</option>
      <option value="s">segundos</option>
      <option value="m">minutos</option>
      <option value="h">horas</option>
      <option value="d">dias</option>
    </select>
  </p>
  <p>Diferença: <span id="resultado"></span></p>
</form>


Difference in months and years

This calculation is already a little more complicated, as already explained here. Many may suggest only to pick up the difference in days and divide by 30 (or by 365.25 / 12, or by any other arbitrary mean value), and then round off the result. But these values will only give you approximations, and are subject to many mistakes.

Using the examples of above mentioned link, between 01/01/2019 and 01/02/2019 31 days ago. Dividing by 30 and rounding, gives 1 month.

But between 01/02/2019 and 01/03/2019 there are 28 days. Dividing by 30, gives 0,93: if round down, gives zero months. But between February 1 and March 1 the difference is not one month? Then we should round up in this case?

But if it was between 01/01/2019 and 29/01/2019, the difference is also 28 days. Only between January 1st and January 29th it hasn’t been 1 month, so I can’t round up in this case. "Ah, so I just jump up if I’m not in the same month".

Then you see that between 01/01/2019 and 27/02/2019 the difference is 57 days, divided by 30 is 1,9. If you round it up, it’s 2, but between January 1st and February 27th it hasn’t been two months. And now?

Dividing by 30 (or any other arbitrary "mean" value) will always have this problem. This is because months have varying sizes (may be 28, 29, 30 or 31 days) and the exact amount of months equivalent to the days will depend on the dates involved. The same goes for years, as they may be 365 or 366 days, and the exact amount of years also depends on the dates involved.

Therefore, an alternative would be to use the same suggested algorithm of above-mentioned answer:

function ajustaMesAno(date) {
    return date.getUTCFullYear() * 12 + date.getUTCMonth();
}

function diffMeses(data1, data2) {
    return ajustaMesAno(data2) - ajustaMesAno(data1);
}

The above code disregards the day of the month (i.e., the difference between any date in January and any date in February is 1 month). But you can also consider that if the initial date is 10/01/2019, then until the day 09/02/2019 has not yet completed 1 month (only from 10/02 is that we can consider that it has already passed 1 month). In that case, the code would be:

function diffMeses(data1, data2) {
    let meses = ajustaMesAno(data2) - ajustaMesAno(data1);
    if (data1.getUTCDate() > data2.getUTCDate()) {
        meses--;
    }
    return meses;
}

Which one is the right one? It depends on how you want to calculate this difference. There is no "official" rule for doing these calculations, as there is in mathematics. What exists are different implementations, and some are more "accepted", but everything depends on each case. Date arithmetic is not obvious at all, and there is several very strange and counter-intuitive cases.

What about years? We can take the difference in months and divide by 12:

function diffAnos(data1, data2){
    return diffMeses(data1, data2) / 12;
}

Whether we will take into account the day of the month or not, this is defined by the implementation we have chosen for diffMeses. If you want, you can still round up the result as desired. That’s up to you.

And then there’s the case of February 29th.

If someone was born on 02/29/2000, on 02/28/2001 can we consider that the person has already been 1 year? After all, there’s still one day left for the anniversary - only the next day is March 1, so how do you do it? Again, there is no official rule for this: some Apis consider the result to be zero years, others consider it to be 1. It is up to you to choose how you treat these cases.

Anyway, date arithmetic isn’t that simple when you start thinking about the details. It’s no wonder there are so many different Apis to work with dates, each taking different approaches, and many are far from being considered successful. Anyway, the "basic" idea was given...


Moment js.

You can use the Moment js., who owns the method diff, much better to work with dates:

function calcula(sel) {
    let data1 = document.getElementById('data1').value;
    let data2 = document.getElementById('data2').value;
    if (data1 && data2) { // se os 2 campos estão preenchidos
        let op = sel.options[sel.selectedIndex];
        let d1 = moment(data1);
        let d2 = moment(data2);
        let diff;
        switch (op.value) {
            case 'ms': // milissegundos, usar o método normal
                diff = d2 - d1;
                break;
            default: // para todos os outros casos, usar o moment
                if (op.value) {
                    diff = d2.diff(d1, op.value);
                }
        }
        if (diff !== undefined) {
            document.getElementById('resultado').innerHTML = `${diff} ${op.text}`;
        }         
    }
}
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<form>
  <p><label class="form">Primeira data:</label><input type="date" class="textbox" id="data1" name="data1" /></p>
  <p><label class="form">Segunda data:</label><input type="date" class="textbox" id="data2" name="data2" /></p>
  <p>Escolha o cálculo:
    <select onchange="calcula(this)">
      <option value="">escolha</option>
      <option value="ms">milissegundos</option>
      <option value="seconds">segundos</option>
      <option value="minutes">minutos</option>
      <option value="hours">horas</option>
      <option value="days">dias</option>
      <option value="months">meses</option>
      <option value="years">anos</option>
    </select>
  </p>
  <p>Diferença: <span id="resultado"></span></p>
</form>

  • 1

    Thank you so much for your help! It helped me understand more about the content itself and I have now managed to complete a part of my project. Thank you very much! From my heart.

  • @Danna I made a correction in function diffMeses, had reversed the date order...

0

Take the result of subtracting the two, in milliseconds, and divide by the value you want.
example:

var horas = Math.abs(data1 - data2) / (60*60*1000);

Obs: Obviously, depending on how you set the input fields, this can return you a decimal number. You will have to decide whether to take only the whole part or round.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.