Code that calculates days between two dates without using the datetime module

Asked

Viewed 2,516 times

1

I’m making a code that calculates the days between two dates, but it cannot use the datetime module, and it only gives error.

Here’s the code:

usuariodata=input()
usuariodata2=input()

Datas=usuariodata.split("/")
Datas1=[int(Datando) for Datando in Datas]

Dia, Mes, Ano = Datas1

MES = Mes-1
NumerosdeDias=0
Contador=1 

while Contador < MES:
    if Contador in (3,5,7,8,10,12):
        NumerosdeDias+=31
    elif Contador in (4,6,9,11):
        NumerosdeDias+=30
    else:
        NumerosdeDias+=28
    Contador+=1

Verifique=(365- NumerosdeDias - Dia - 1)

Datas2=usuariodata2.split("/")
Datas3=[int(Datador) for Datador in Datas2]

Dia1, Mes1, Ano1= Datas3

ANO= Ano1-1
MES1 = Mes1-1
NumeroDeDias=0 
Contadores=1 

while Contadores <= MES1:
  if Contadores in (4,6,9,11):
    NumeroDeDias+=30
  elif Contadores in (1,3,5,7,8,10):
    NumeroDeDias+=31
  else:
    NumeroDeDias+=28
  Contadores+=1
Verificador = (365- NumeroDeDias - Dia1 - 23)

AnoFinal=(Ano1-Ano)
AnoFinal2=AnoFinal*365

if Ano%4 ==0:
  if Mes==2 and Dia==28:
    bissexto=(Ano1-Ano)//4
  else:
    bissexto=(Ano1-Ano)//4-1
elif Ano%4==0:
  if Mes1 ==2:
     bissexto=(Ano1-Ano)//4
  else:
    bissexto=(Ano1-Ano)//4-1
else:
  bissexto=(Ano1-Ano)//4

Verificando = AnoFinal2-bissexto
print(Verifique+Verificador +Verificando)

Link from where it can be run: https://repl.it/F7rr/2

  • This may help you: http://answall.com/a/70604/132

  • 1

    Ah, it is important to note that, in order to correct a 3-day error that accumulated every 400 years, Pope Gregory XIII determined in 1582 a reform of the calendar that made not every year divisible by 4 leap. Thus, 1700, 1800 and 1900 were not leap. 2100, 2200 and 2300 also will not be. But 1600, 2000 and 2400 are leap. Your program doesn’t take that into account and therefore misses calculations.

  • Fellow @Victorstafusa noted very well. If your doubt is the algorithm that does what he said, your question is more or less duplicated because here is the answer (though not in the same language).

  • Man ... if you’re going to subtract or command dates without using datetime, you’re already wrong to start. Unless it’s just to learn it, the ut er you like to do it, use datetime. Do not try to redo this code and put it into production. MICROSOFT has put wrong code for dates in the first 5-10 years of Excel - dates are very easy to miss, and very critical for any system in production.

  • Is there anything that does not answer you in the answer below? If it worked, you can mark it as accepted?

1 answer

5

Your code has some strange things. The first is about the dubious name chosen for most variables (e.g.: Datas, Datas1, Datas2 and Datas3). I will rename them. And by renaming, I will take into account the python variable naming convention.

Another problem is in relation to things like this:

Verificador = (365- NumeroDeDias - Dia1 - 23)

Where did this 23 come from?

Ah, it is important to note that, in order to correct a 3-day error that accumulated every 400 years, Pope Gregory XIII determined in 1582 a reform of the calendar that made not every year divisible by 4 leap. Thus, 1700, 1800 and 1900 were not leap. 2100, 2200 and 2300 also will not be. But 1600, 2000 and 2400 are leap. Your program doesn’t take that into account and therefore misses calculations.

I ran a test on your program and clearly there’s something very wrong with it:

 28/02/1900
 01/03/1900
618
 10/10/2010
 11/10/2010
172

Well, let’s organize it all. First I noticed this:

if mes in (3, 5, 7, 8, 10, 12):

Where is January? The 1 should be there too!

Watch this one of yours if:

if Ano%4 ==0:
    # ...
elif Ano%4==0:

If Ano%4==0, the if enters, but the elif no. Otherwise neither of the two enter. Anyway, the elif never enters!

You are calculating the leap numbers by subtracting the years numbers and dividing by 4. This does not work because if you consider a period from 2016 to 2017, the leap day will only count if the start is before the first of March. Already in a period from 2015 to 2016, the leap day will count only if the final date is after 29/02. You only check the day 28/02 specifically, but this is insufficient to catch the leap day of a period such as for example, 08/03/2015 to 08/03/2016.

To fix the problem I described in the previous paragraph, one way is to count the leap years (and only then), you count for years that start on 01/03, as if January and February were the last months instead of being the first. To do this, just subtract 1 year if it’s January or February.

Finally, this one of yours while with a if inside can be separated into a function to avoid having to duplicate it. I also put the whole procedure of calculating the difference in dates in a function.

In case the second date is earlier than the first, to avoid misspelling calculations, we can reverse the dates and then consider the negative result.

And finally, to handle cases where the user enters invalid dates such as 32/10/2017, 29/02/2017, 00/00/0000, 99/99/9999 ab/cd/efgh, sorvete-de-abacaxi, etc, I use the python exception handling. To help in this process, I created the functions bissexto, determining whether a year is leap and validar_data determining whether a date is valid or not.

So here’s the resulting code:

def dia_no_ano(dia, mes, ano):
  numero_de_dias = dia
  contador_meses = 1
  while contador_meses < mes:
    if contador_meses in (1, 3, 5, 7, 8, 10, 12):
      numero_de_dias += 31
    elif contador_meses in (4, 6, 9, 11):
      numero_de_dias += 30
    elif contador_meses == 2:
      numero_de_dias += 28
    contador_meses += 1
  return numero_de_dias

def bissexto(ano):
  return ano % 4 == 0 and (ano % 100 != 0 or ano % 400 == 0)

def validar_data(dia, mes, ano):
  if dia < 1 or dia > 31 or mes < 1 or mes > 12 or ano < 1583:
    return False
  if mes in (4, 6, 9, 11) and dia == 31:
    return False
  if mes == 2 and dia >= 30:
    return False
  if mes == 2 and dia == 29 and not bissexto(ano):
    return False
  return True

def diferenca_data(data1, data2):

  # Separa os dados adequadamente e trata entradas mal-formadas.
  try:
    dia1, mes1, ano1 = [int(datando) for datando in data1.split("/")]
  except ValueError:
    raise ValueError('Data inválida: ' + data1)

  try:
    dia2, mes2, ano2 = [int(datador) for datador in data2.split("/")]
  except ValueError:
    raise ValueError('Data inválida: ' + data2)

  # Verifica se as datas entradas são válidas:
  if not validar_data(dia1, mes1, ano1):
    raise ValueError('Data inválida: ' + data1)
  if not validar_data(dia2, mes2, ano2):
    raise ValueError('Data inválida: ' + data2)

  # Inverte as datas se a data2 anteceder a data1.
  if ano2 < ano1 or (ano2 == ano1 and (mes2 < mes1 or (mes2 == mes1 and dia2 < dia1))):
    return -diferenca_data(data2, data1)

  # Calcula o número de dias nos anos incompletos.
  dias_ano1 = dia_no_ano(dia1, mes1, ano1)
  dias_ano2 = dia_no_ano(dia2, mes2, ano2)

  # Calcula o número de dias totais, considerando os anos incompletos e anos completos de 365 dias.
  dias_total = dias_ano2 - dias_ano1 + (ano2 - ano1) * 365

  # Considera anos começando em 01/03 para poder fazer a correção dos anos bissextos.
  ano1b = ano1
  if mes1 < 3:
    ano1b -= 1

  ano2b = ano2
  if mes2 < 3:
    ano2b -= 1

  # Soma os dias dos anos bissextos. São os divisíveis por 4 que ocorrem entre ano1b e ano2b.
  dias_total += int(ano2b / 4) - int(ano1b / 4)

  # Subtrai os dias dos anos bissextos que não existiram na etapa anterior. São os divisíveis por 100.
  dias_total -= int(ano2b / 100) - int(ano1b / 100)

  # Soma de volta os dias dos anos bissextos que foram removidos a mais na etapa anterior. São os divisíveis por 400.
  dias_total += int(ano2b / 400) - int(ano1b / 400)

  # Resultado da função.
  return dias_total

####### Início do programa. #######

# Lê a entrada do usuário.
x = input()
y = input()

# Calcula a diferença.
diferenca = diferenca_data(x, y)

# Mostra o resultado.
print(diferenca)

I also did the following tests:

# Testes
print('Testes:')
print(diferenca_data('28/02/1900', '01/03/1900')) # 1 dia.
print(diferenca_data('28/02/1904', '01/03/1904')) # 2 dias.
print(diferenca_data('28/02/2000', '01/03/2000')) # 2 dias.
print(diferenca_data('01/01/2016', '31/12/2016')) # 365 dias.
print(diferenca_data('01/01/2016', '01/01/2017')) # 366 dias.
print(diferenca_data('01/01/2017', '31/12/2017')) # 364 dias.
print(diferenca_data('01/01/2017', '01/01/2018')) # 365 dias.
print(diferenca_data('10/10/2010', '10/10/2410')) # 146097 dias.
print(diferenca_data('01/01/2018', '01/01/2017')) # -365 dias.
print(diferenca_data('01/01/2017', '01/01/2016')) # -366 dias.
print(diferenca_data('01/01/1899', '01/01/1903')) # 1460 dias.
print(diferenca_data('01/01/1900', '01/01/1904')) # 1460 dias.
print(diferenca_data('01/01/1901', '01/01/1905')) # 1461 dias.
print(diferenca_data('01/01/2000', '01/01/2004')) # 1461 dias.

# Datas válidas.
print('Datas válidas:')
print(validar_data(1, 1, 2001))
print(validar_data(1, 1, 1583))
print(validar_data(31, 12, 99999))
print(validar_data(31, 1, 2016))
print(validar_data(28, 2, 1900))
print(validar_data(28, 2, 2017))
print(validar_data(29, 2, 2000))
print(validar_data(29, 2, 2016))
print(validar_data(31, 3, 2016))
print(validar_data(30, 4, 2016))
print(validar_data(31, 5, 2016))
print(validar_data(30, 6, 2016))
print(validar_data(31, 7, 2016))
print(validar_data(31, 8, 2016))
print(validar_data(30, 9, 2016))
print(validar_data(31, 10, 2016))
print(validar_data(30, 11, 2016))
print(validar_data(31, 12, 2016))

# Datas inválidas:
print('Datas inválidas:')
print(validar_data(0, 1, 2001))
print(validar_data(-1, 1, 2001))
print(validar_data(1, 0, 2001))
print(validar_data(1, -1, 2001))
print(validar_data(1, 13, 2001))
print(validar_data(1, 1, 1582))
print(validar_data(32, 1, 2016))
print(validar_data(31, 2, 2016))
print(validar_data(30, 2, 2016))
print(validar_data(29, 2, 1900))
print(validar_data(29, 2, 2017))
print(validar_data(32, 3, 2016))
print(validar_data(31, 4, 2016))
print(validar_data(32, 5, 2016))
print(validar_data(31, 6, 2016))
print(validar_data(32, 7, 2016))
print(validar_data(32, 8, 2016))
print(validar_data(31, 9, 2016))
print(validar_data(32, 10, 2016))
print(validar_data(31, 11, 2016))
print(validar_data(32, 12, 2016))

The output was exactly as expected for all tests.

See all this working on repl it..

Browser other questions tagged

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