Make an algorithm to calculate the number of days elapsed between two dates in c++

Asked

Viewed 31,930 times

7

Guys I have this algorithm:

Make an algorithm to calculate the number of days elapsed between two dates (also consider the occurrence of leap years), knowing that: a) each pair of dates is read on a line, the last line contains the negative day number b) the first date on the line is always a older. The year is typed with four digits.

I was able to make the program calculate the days from year 1 to year 2 as it is in my code:

#include<iostream>

int main(){

    int dia1, mes1, ano1, dia2, mes2, ano2, diaTotalAno;

    dia1 = 12;
    mes1 = 03;
    ano1 = 2011;

    dia2 = 05;
    mes2 = 10;
    ano2 = 2014;

    // Pega os dias entre ano1 e ano2
    for(int i = ano1; i < ano2; i++){ 

        // verifica se ano é bissexto ou não
        if(i % 4 == 0){
            diaTotalAno += 366;
        } else {
            diaTotalAno += 365;
        }
    }

    for(int i = ano1; i < ano2; i++){ 
        int diaMes +=30;  
    }

    std::cout << "Os dias entre " << ano1 << " e " << ano2 << " é: " << diaTotalAno << "\n";

    return 0;
}

But I am not able to calculate the months or the days. It has how to help me to arrive at a solution?

  • 2

    I don’t know much about C++, but how about converting the two dates to timestamps (in seconds), taking the difference, and then dividing by 86400 (24 * 60 * 60)?

  • This algorithm is a college exercise, and I can only use if, for and variables, so q complicates a lot.

  • 1

    This is not an algorithm. It’s a problem :B

  • Anyway, if you can find the amount of days gone by, why not just turn the days into day/month/year?

3 answers

18


WARNING: You say clearly that this is a college job. So there is all this need to understand how work the calculations and implement them manually. In the "real world" it would be easier already to reuse something ready, which usually already exists in programming languages or libraries (as in Qt, for example, in the class Qdatetime).

Anyway, I am posting this answer in order to help other people who have doubts and/ or needs similar, especially as there are a number of important concepts involved. Please don’t understand that I made the code for you. If you feel tempted to use it at your work without worrying to understand how it works, well, the choice is yours. The intention of college jobs is to make the student learns, and if you simply copy you will just be squandering your time unnecessarily. The message was given.

The simplest solution is direct has already been provided to you in a comment: if you convert both dates to seconds and then make a difference, you can split this result in seconds by 86400 to have the difference in days. You could convert the dates directly to days, but the conversion to seconds is better because it allows you to also work with schedules (i.e., have a Date structure instead of a Date-only structure).

Important Conceptual Issues

First of all, there are some conceptual questions very important:

  1. To find out if a year is leap is not enough check if it is divisible by 4. Leap years exist as a way to adjust the calendar due to the fact that the earth does not rotate exactly 365 times around you throughout the year, but yes about 365,242375 times. Because of that difference, was agreed to adjust as follows:

    • Every 4 years an extra day is added (29 February), making it 365.25 days per year (when counted in intervals of 4 every 4 years). This is a good approximation, but still with an approximate error of 1 day every 100 years (0.01 * 100 = 1).
    • Therefore, every 100 years do not add the extra day, ie the year (although divisible by 4) is not leap (e.g., 1700, 1800, 1900, 2100, etc.). Thus, there is a total of 365.24 days per year (when counted in intervals of 100 years). This is a much better approximation, but still with significant error of nearly 1 day every 400 years (0.002375 * 400 1).
    • Thus, the last rule is to add 1 day every 400 years (even though the year is divisible by 100), making the rest of the difference practically solved and having a value very close to 365 days per year (when counted in 400-year intervals).
  2. If you convert the dates to seconds, you will need to reference some initial date (that is, when the counting in seconds actually started). It is common to use the date 00:00:00 01/01/0001 as reference, as it marks the positive beginning of the gregorian calendar (zero hour, first day, first month, first year). For example, with this reference can be said that date 00:00:00 12/03/2011 is equivalent to 63,435,484,800 seconds (since 00:00:00 01/01/0001). It should be possible to realize that the number of seconds is biggie (over 63 billion seconds), and so you cannot treat it in your program using simple integer values (whose maximum value is 4 billion, with no signal on 32-bit architecture). That’s why in the example code I used as data type the unsigned long long, whose size depends on the platform but is guaranteed by the Standard C99 to have at least 64 bits for representation (allowing to store very large whole numbers, in the order of 1018 unsigned).

  3. You also need to set for the compiler that the literal integer values typed (the 86400 from the comment you received, for example) is a long value. So you does not incur precision errors in the calculations. To do this, just add LL in front of the literal number, doing, for example:

unsigned long long segundos = 86400LL;
  1. Tome very carefully when representing literal numbers in code written in C/C++ with a zero digit (0) left. In the notation of these languages, this indicates a literal number in the octal system (base 8) and not in the decimal system (base 10). Thus, 03 (octal) is equal to 3 (decimal), but 0016 (octal) shall not be equal to 16 (decimal), but equal to 14 (decimal). If you intend to write the year this way, you will not have the year you expect. By the way, if you try to write the month 08 thus, you will get a compilation error indicating, for example (in my compiler, VS 2012):
error C2041: illegal digit '8' for base '8'

This error occurs because in the octal system the usable digits go only from 0 to 7 (as in the decimal system they go from 0 to 9). So when setting your dates, use the literal numbers without the leading zeros for no problems. More information in this SOEN question.

The Implementation

Based on these explanations, here is an example of code that can be built to perform the calculations. You can check the result by comparing it with other sources, such as this site that calculates the difference between dates. The site only represents the dates, and the example I provide also allows you to represent the time (in hours, minutes and seconds). So when creating comparative dates, don’t forget to set the time, minute and second to 0. The example below tests the dates you provide yourself in the question.

#include <stdio.h>

/* Estrutura para representar uma DataHora */
typedef struct _MinhaDataHora {
    int hora;
    int minuto;
    int segundo;
    int dia;
    int mes;
    int ano;
} MinhaDataHora;

/* Função auxiliar para definir os valores da estrutura DataHora */
void defineDataHora(MinhaDataHora *pd, int hora, int minuto, int segundo, int dia, int mes, int ano)
{
    pd->hora = hora;
    pd->minuto = minuto;
    pd->segundo = segundo;
    pd->dia = dia;
    pd->mes = mes;
    pd->ano = ano;
}

/* Função auxiliar para imprimir os valores da estrutura DataHora formatados */
void imprimeDataHora(MinhaDataHora d)
{
    printf("%02d:%02d:%02d %02d/%02d/%04d", d.hora, d.minuto, d.segundo, d.dia, d.mes, d.ano);
}

/* Função para verificação se um ano é bissexto */
bool ehBissexto(int ano)
{
    /*
      Um ano só é bissexto se ele for divisível por 4 e NÃO FOR divisível por 100
      (a não ser que ele seja divisível por 100 E TAMBÉM divisível por 400).
    */
    return (ano % 4 == 0) && (ano % 100 != 0 || ano % 400 == 0);
}

/* Função para contar quantos anos bissextos tem entre o ano 1/1/1 e o ano dado */
int contaBissextos(int ano)
{
    return (ano / 4) - (ano / 100) + (ano / 400);
}

/* Função para converter a DataHora dada para segundos */
unsigned long long dataParaSegundos(MinhaDataHora d)
{
    unsigned long long total = 0LL;

    /*
     Primeiro, calcula o tempo decorrido em segundos até a data
     sem contar os anos bissextos, considerando:

     31536000 = número de segundos em um ano não bissexto (365 dias)
     86400 = número de segundos em um dia (24 horas)
     3600 = número de segundos em 1 hora (60 minutos)
     60 = número de segundos em 1 minuto (60 segundos)
    */

    total += (d.ano - 1) * 31536000LL;

    int meses[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    for(int mes = 1; mes < d.mes; mes++)
        total += meses[mes-1] * 86400LL;

    total += (d.dia - 1) * 86400LL;

    total += d.hora * 3600LL;

    total += d.minuto * 60LL;

    total += d.segundo;

    /*
     Então, adiciona segundos para cada dia adicional dos anos bissextos
    */

    /* Número de dias adicionais, para os anos bissextos anteriores ao ano atual */
    int diasExtras = contaBissextos(d.ano - 1);
    total += diasExtras * 86400LL;

    /* Se o mês da data já passou de fereveiro e o ano atual é bissexto, adiciona mais um dia */
    if(ehBissexto(d.ano) && (d.mes - 1) >= 2)
        total += 86400LL;

    return total;
}

/* Função para o cálculo da diferença em segundos entre duas datas */
unsigned long long calculaDiferencaEmSegundos(MinhaDataHora d1, MinhaDataHora d2)
{
    unsigned long long segundosd1 = dataParaSegundos(d1);
    unsigned long long segundosd2 = dataParaSegundos(d2);

    if(segundosd1 > segundosd2)
        return segundosd1 - segundosd2;
    else
        return segundosd2 - segundosd1;
}

/* Função para o cálculo da diferença em dias entre duas datas */
unsigned long long calculaDiferencaEmDias(MinhaDataHora d1, MinhaDataHora d2)
{
    unsigned long long segundos = calculaDiferencaEmSegundos(d1, d2);
    return segundos / 86400LL;
}

/* Função principal do programa */
int main(int argc, char **argv)
{
    MinhaDataHora d1, d2;
    defineDataHora(&d1, 0, 0, 0, 12, 3, 2011);
    defineDataHora(&d2, 0, 0, 0, 5, 10, 2014);

    printf("d1: ");
    imprimeDataHora(d1);
    printf(" (em segundos: %llu)\n", dataParaSegundos(d1));
    printf("d2: ");
    imprimeDataHora(d2);
    printf(" (em segundos: %llu)\n\n", dataParaSegundos(d2));

    printf("Diferenca em segundos entre d1 e d2: %llu\n", calculaDiferencaEmSegundos(d1, d2));
    printf("Diferenca em dias entre d1 e d2: %llu\n", calculaDiferencaEmDias(d1, d2));

    return 0;
}

This program results in the following output:

d1: 00:00:00 12/03/2011 (em segundos: 63435484800)
d2: 00:00:00 05/10/2014 (em segundos: 63548064000)

Diferenca em segundos entre d1 e d2: 112579200
Diferenca em dias entre d1 e d2: 1303

The main function is dataParaSegundos, that really makes the suggested conversion into comment. Basically it works as follows:

  1. Given a date, for example 00:00:00 12/03/2011, it starts by counting the total number of seconds that have passed until the previous year (in the example, 2010). Simply because it was only so far that it has passed full years (that is, 2011 is still in progress and so cannot be considered complete). Thus, the total in seconds is accumulated with (d.ano - 1) * 31536000LL: are 2010 years times the total in seconds of a non-leap year (this "magic" number is equal to that suggested in the commentary, but calculated as 60 x 60 x 24 x 365, that is, 60 seconds x 60 minutes, to have the seconds in 1 hour; x 24 hours, to have the seconds in 1 day; x 365, to have the seconds in 1 year).
  2. The months are calculated in a similar way (considering only until the previous one, because the current one is not yet "complete"), but need to be accumulated one by one because they have different days quantities (therefore the for instead of multiplying by a single value).
  3. The days are done in the same way, considering only until the previous one (because the current day is also not complete - it will have a few hours, minutes and seconds elapsed until 23:59:59, when it will change to the next day).
  4. Only the hours, minutes and seconds that are normally accumulated, because they do not represent the incomplete current value, but what has already been completed (2:31:10 indicate exactly this: 2 hours, 31 minutes and 10 seconds have passed).
  5. Since these calculations intentionally ignore leap years, just add as many days as necessary for the leap years that occurred between 1/1/1 and the previous year. In the case of the current year, only 1 day should be added if the date is past February (because even if it is leap, if it is still January it makes no sense to add 1 day).

The rest of the functions are self-explanatory, mainly based on the conceptual issues previously discussed.

  • 1

    Congratulations, great answer.

4

Well, because it’s a college exercise, I’m not going to post the full code here, but a draft for the algorithm.

Let D1,M1 and a1 be the values of the day, month and year of the oldest date and D2,m2 and a2 values of the new date.

First we need to define the difference of days between years only. We can use a for that increments 1 every time we pass a divisible year by 4 between the years of the input values. The end result will be (a2-a1)*(365) + flag_bissexto which marks how many days have been added by the leap year.

As we have months of 28.30 and 31 days, we need to calculate the difference correctly. Thus we identify M1 through Ifs as if(m1%30) or if(m1%31) or if(m1%28).

After that, we need to find out how many days make up the difference between D1/M1-D2/m2. If we realize that M1=m2, we can make the difference of direct days. Otherwise, we will need another calculation (here being a case of common if Else). Defining something like ja=31,fe=28,mar=31,ab=30,mai=31,jun=30 And so on, we can do a go that increments a variable by 1 every time a day goes by, and count back to the end of the month. When we have counted every day of the month, we can add the remaining months directly to reach m2, when we add only D2 to the result. Note that every odd month has 31 days, and every even month other than 2(February) has 30.

In practice, it would be something like:

D1/M1/a1 = 22/04/1993

D2/m2/a2 = 26/01/2015

(2015-1993)*365 + (5) will be the day difference between the two years with the following years as leap years:1996,2000,2004,2008,2012.

As we want to do D1/M1-D2/m2, in this example we will have a negative result, but it will be natural and correct, since from April to January "we will advance negative days".

Thus we will have -D1(22)-mar(31)-feb(28)-jan(31)+26 = -22-31-28-31(At this point we are on day 1/1, so we add 26 to get to the correct date)+26 the difference in days.

To obtain the final result just add the difference of days of the years with the difference of days of D1/M1=D2/m2.

I hope I’ve helped

0

Follow the code in C Language that does exactly what you asked. I developed this code as an exercise fix. 18/09/2020. I hope to help those who need it. Analyze the code, not just copy it. Your learning depends on it. Developed by Jaime Ribeiro Júnior.

#include<stdio.h>
main()
{
    int anoi = 0, anof = 0, quantDias = 0, diai=0, diaf=0;
    int mesi=0, mesf =0, anopro = 0, mespro = 0;
    
    printf("Digite o ano inicial -> ");
    scanf("%d/%d/%d", &diai, &mesi, &anoi); getchar();
    printf("Digite o ano final -> ");
    scanf("%d/%d/%d", &diaf, &mesf, &anof); getchar();
    anopro = anoi+1;

    if(anoi != anof){ //ano inical e final diferentes
            //avaliar os anos intermerdiarios 
            // que possuem a quantidade completa de dias
        while(anopro < anof){
            if(anopro%400 == 0) quantDias = quantDias + 366;
            else if(anopro%100 != 0 && anopro%4 == 0) quantDias = quantDias + 366;
            else quantDias = quantDias + 365;
            //printf("dias %d + ", quantDias);// impressão de teste
            anopro++;
        }
        //para ano inicial diferente de ano final.
        //Calculo no ano inicial
        mespro = mesi;
        while(mespro <= 12){
            if(mespro == mesi){//verificação do mês inicial, precisa descontar a quantidade de dias corridos
                if(mesi <= 7 && mesi%2 == 1) quantDias+=31 - (diai - 1);
                //verficande de janeiro a julho
                else if (mesi <= 7 && mesi%2 == 0 && mesi != 2) quantDias+=30 - (diai - 1);
                else if(mesi == 2){
                if(anoi%400 == 0) quantDias = quantDias + 29 - (diai - 1);//C espressão normal
                else if(anoi%100 != 0 && anoi%4 == 0) quantDias += 29 - (diai - 1);//C reduzido
                else quantDias += 28 - (diai - 1);
                } //verificando de agosto a dezembro
                else if(mesi > 7 && mesi%2== 0) quantDias+=31 - (diai - 1);
                else if(mesi > 7 && mesi%2== 1) quantDias+=30 - (diai - 1);
            } else{ //verficação de mês diferente do mês inical
                //verficande de janeiro a julho
                if(mespro <= 7 && mespro%2 == 1) quantDias+=31;// C reduzido 
                else if (mespro <= 7 && mespro%2 == 0 && mespro != 2) quantDias+=30;
                else if(mespro == 2){
                    if(anoi%400 == 0) quantDias = quantDias + 29;// Espressão normal
                    else if(anoi%100 != 0 && anoi%4 == 0) quantDias += 29;//C reduzido
                    else quantDias += 28;
                }//verificando de agosto a dezembro
                else if(mespro > 7 && mespro%2== 0) quantDias+=31;
                else if(mespro > 7 && mespro%2== 1) quantDias+=30;
            }

            mespro++;           
        }
    //printf("dias %d + ", quantDias);// impressão de teste
    //Calculo ano final
        mespro = mesf;
        while (mespro >= 1)
        {
            if(mespro == mesf){//verificação do mês final, só conta a quantidade de dias corridos
                 quantDias+= diaf;
                 
            } else{ //verficação de mês diferente do mês final 
                if(mespro <= 7 && mespro%2 == 1) quantDias+=31;//janeiro a julho
                else if (mespro <= 7 && mespro%2 == 0 && mespro != 2) quantDias+=30;
                else if(mespro == 2){
                    if(anof%400 == 0) quantDias += 29;
                    else if(anof%100 != 0 && anof%4 == 0) quantDias += 29;
                    else quantDias += 28;
                } //agosto a dezembro
                else if(mespro > 7 && mespro%2== 0) quantDias+=31;
                else if(mespro > 7 && mespro%2== 1) quantDias+=30;
            }   
        mespro--;   
        }
    //_________________________________________________________________________________________
    } else {// para ano inicial e ano final iguais
            mespro = mesi;
        while(mespro < mesf){
            if(mespro == mesi){//verificação do mês inicial, precisa descontar a quantidade de dias corridos
                if(mesi <= 7 && mesi%2 == 1) quantDias+=31 - (diai - 1);
                //verficande de janeiro a julho
                else if (mesi <= 7 && mesi%2 == 0 && mesi != 2) quantDias+=30 - (diai - 1);
                else if(mesi == 2){
                if(anoi%400 == 0) quantDias = quantDias + 29 - (diai - 1);//C espressão normal
                else if(anoi%100 != 0 && anoi%4 == 0) quantDias += 29 - (diai - 1);//C reduzido
                else quantDias += 28 - (diai - 1);
                } //verificando de agosto a dezembro
                else if(mesi > 7 && mesi%2== 0) quantDias+=31 - (diai - 1);
                else if(mesi > 7 && mesi%2== 1) quantDias+=30 - (diai - 1);
            } else{ //verficação de mês diferente do mês inical
                //verficande de janeiro a julho
                if(mespro <= 7 && mespro%2 == 1) quantDias+=31;// C reduzido 
                else if (mespro <= 7 && mespro%2 == 0 && mespro != 2) quantDias+=30;
                else if(mespro == 2){
                    if(anoi%400 == 0) quantDias = quantDias + 29;// Espressão normal
                    else if(anoi%100 != 0 && anoi%4 == 0) quantDias += 29;//C reduzido
                    else quantDias += 28;
                }//verificando de agosto a dezembro
                else if(mespro > 7 && mespro%2== 0) quantDias+=31;
                else if(mespro > 7 && mespro%2== 1) quantDias+=30;
            }
            
            mespro++;           
        }
        quantDias+= diaf; // recebendo dias do mes final
    }
    //printf("dias %d", quantDias);// impressão de teste
    
    printf("\nA quantidade de dias foi de %d", quantDias);
}

Browser other questions tagged

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