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:
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).
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).
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;
- 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:
- 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).
- 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).
- 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).
- 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).
- 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.
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
)?– bfavaretto
This algorithm is a college exercise, and I can only use if, for and variables, so q complicates a lot.
– Samuel Carvalho
This is not an algorithm. It’s a problem :B
– user2692
Anyway, if you can find the amount of days gone by, why not just turn the days into day/month/year?
– user2692