Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: NicolasPileci en 12 Mayo 2017, 20:50 pm



Título: Programas para calcular fechas
Publicado por: NicolasPileci en 12 Mayo 2017, 20:50 pm
Estimados,

Serian tan amables de indicarme que error tengo en estos dos programas:

1 - "Calcular fecha siguiente" (Me devuelve la misma fecha siempre)

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. typedef struct
  5. {
  6.    int dia,
  7.        mes,
  8.        año;
  9. }   tFecha;
  10.  
  11. void calcularFechaSiguiente (tFecha fecha);
  12.  
  13. int main()
  14. {
  15.    system ("color 0a");
  16.    tFecha fecha;
  17.    printf("Ingrese dia: \n\n");
  18.    scanf("%d",&fecha.dia);
  19.    printf("\nIngrese mes: \n\n");
  20.    scanf("%d",&fecha.mes);
  21.    printf("\nIngrese año: \n\n");
  22.    scanf("%d",&fecha.año);
  23.    calcularFechaSiguiente (fecha);
  24.    printf("\nFecha final: %d/%d/%d",fecha.dia,fecha.mes,fecha.año);
  25.    return 0;
  26. }
  27.  
  28. void calcularFechaSiguiente (tFecha fecha)
  29. {
  30.    if(fecha.mes == 4 || fecha.mes == 6 || fecha.mes == 9 || fecha.mes == 11)
  31.    {
  32.        if(fecha.dia == 30)
  33.        {
  34.            fecha.dia = 1;
  35.            fecha.mes++;
  36.        }
  37.        else
  38.            fecha.dia++;
  39.    }
  40.    if(fecha.mes == 2)
  41.    {
  42.        if ((fecha.año % 4 == 0) && ((fecha.año % 100 != 0) || (fecha.año % 400 == 0)))
  43.        {
  44.            if(fecha.dia == 29)
  45.            {
  46.                fecha.dia = 1;
  47.                fecha.mes++;
  48.            }
  49.            else
  50.                fecha.dia++;
  51.        }
  52.        if(fecha.dia == 28)
  53.        {
  54.            fecha.dia = 1;
  55.            fecha.mes++;
  56.        }
  57.        else
  58.            fecha.dia++;
  59.    }
  60.    if(fecha.mes == 1 || fecha.mes == 3 || fecha.mes == 5 || fecha.mes == 7 || fecha.mes == 8 || fecha.mes == 10)
  61.    {
  62.        if(fecha.dia == 31)
  63.        {
  64.            fecha.dia = 1;
  65.            fecha.mes++;
  66.        }
  67.        else
  68.            fecha.dia++;
  69.    }
  70.    if(fecha.dia == 31)
  71.    {
  72.        fecha.dia = 1;
  73.        fecha.mes = 1;
  74.        fecha.año++;
  75.    }
  76.    else
  77.        fecha.dia++;
  78. }

1 - "Calcular dias entres dos fechas" (Me devuelve un resultado cualquiera)

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. typedef struct
  5. {
  6.    int dia,
  7.        mes,
  8.        año;
  9. }   tFecha;
  10.  
  11. long calcularFecha (tFecha fecha1, tFecha fecha2);
  12.  
  13. int main()
  14. {
  15.    system ("color 0a");
  16.    tFecha fecha1,
  17.           fecha2;
  18.    long num;
  19.    printf("Ingrese dia - Primera fecha: \n\n");
  20.    scanf("%d",&fecha1.dia);
  21.    printf("\nIngrese mes - Primera fecha: \n\n");
  22.    scanf("%d",&fecha1.mes);
  23.    printf("\nIngrese año - Primera fecha: \n\n");
  24.    scanf("%d",&fecha1.año);
  25.    printf("\nIngrese dia - Segunda fecha: \n\n");
  26.    scanf("%d",&fecha2.dia);
  27.    printf("\nIngrese mes - Segunda fecha: \n\n");
  28.    scanf("%d",&fecha2.mes);
  29.    printf("\nIngrese año - Segunda fecha: \n\n");
  30.    scanf("%d",&fecha2.año);
  31.    num = calcularFecha (fecha1, fecha2);
  32.    printf("\nDias entre las dos fechas: %d.\n",num);
  33.    return 0;
  34. }
  35.  
  36. long calcularFecha (tFecha fecha1, tFecha fecha2)
  37. {
  38. long num = 0,
  39.        i;
  40. if(fecha1.año < fecha2.año)
  41.        for(i=fecha1.año;i<fecha2.año;i++)
  42.        {
  43.            if ((i % 4 == 0) && ((i % 100 != 0) || (i % 400 == 0)))
  44.                num += i*366;
  45.            else
  46.                num += i*365;
  47.        }
  48.    else
  49.        for(i=fecha2.año;i<fecha1.año;i++)
  50.        {
  51.            if ((i % 4 == 0) && ((i % 100 != 0) || (i % 400 == 0)))
  52.                num += i*366;
  53.            else
  54.                num += i*365;
  55.        }
  56.    if(fecha1.mes < fecha2.mes)
  57.        for(i=fecha1.mes;i<fecha2.mes;i++)
  58.        {
  59.            if(i == 4 || i == 6 || i == 9 || i == 11)
  60.                num += i*30;
  61.            if(i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12)
  62.                num += i*31;
  63.            if(i == 2)
  64.                num += i*28;
  65.        }
  66.    else
  67.        for(i=fecha2.mes;i<fecha1.mes;i++)
  68.        {
  69.            if(i == 4 || i == 6 || i == 9 || i == 11)
  70.                num += i*30;
  71.            if(i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12)
  72.                num += i*31;
  73.            if(i == 2)
  74.                num += i*28;
  75.        }
  76. if(fecha1.dia > fecha2.dia)
  77.        num += fecha1.dia - fecha2.dia;
  78. else
  79. num += fecha2.dia - fecha1.dia;
  80.    return num;
  81. }
  82.  

Desde ya muchas gracias.
Saludos!


Título: Re: Programas para calcular fechas
Publicado por: MAFUS en 12 Mayo 2017, 21:05 pm
En el primero programa pasas la estructura por valor. Todos los cambios que hagas dentro de la función no se reflejarán fuera de ella, por eso debes pasarla por referencia (un puntero de ella o su dirección) y cuidado con el cambio de acceso a los datos del puntero a la estructura.

Para el segundo programa observa lo siguiente:
Código
  1. if(fecha1.año < fecha2.año)
  2.        for(i=fecha1.año;i<fecha2.año;i++)
  3.        {
  4.            if ((i % 4 == 0) && ((i % 100 != 0) || (i % 400 == 0)))
  5.                num += i*366;
  6.            else
  7.                num += i*365;
  8.        }

Fíjate que num va a tener el número erróneo de días por la simple razón de:
Supongamos que el año es el 2000. Pues en la primera iteración del bucle será 2000*365, a este número, en la segunda iteración será 2000 * 365 + 2001 * 365 y así. La fórmula está mal.


Título: Re: Programas para calcular fechas
Publicado por: NicolasPileci en 23 Mayo 2017, 20:57 pm
Estimado,

Gracias por tu respuesta. Surgio otro problema dentro del primer programa y es que cuando ingreso un dia 30 y un mes 4, el resultado obtenido es 2/05/17. No puedo hallar el error.

Gracias!


Título: Re: Programas para calcular fechas
Publicado por: MAFUS en 23 Mayo 2017, 21:45 pm
Error de lógica. Tal como lo tienes tu programa hace lo siguiente:
Código
  1. if(fecha.mes == 4 || fecha.mes == 6 || fecha.mes == 9 || fecha.mes == 11)
  2. {
  3.    if(fecha.dia == 30)
  4.    {
  5.        fecha.dia = 1;
  6.        fecha.mes++;
  7.    }
  8.    else
  9.        fecha.dia++;
  10. }
  11.  
  12. // ...
  13.  
  14. if(fecha.dia == 31)
  15. {
  16.    fecha.dia = 1;
  17.    fecha.mes = 1;
  18.    fecha.año++;
  19. }
  20. else
  21.    fecha.dia++;

Cómo puedes ver ese último if de la función se ejecuta y como no es día 31 te sumará un día más.


Título: Re: Programas para calcular fechas
Publicado por: NicolasPileci en 24 Mayo 2017, 14:45 pm
Perdon,

Ya corregi el codigo, pero aun me sigue sumando un dia de mas en los meses de 30 dias.

Código
  1. void calcularFechaSiguiente (tFecha *fecha)
  2. {
  3.    if(fecha->mes == 4 || fecha->mes == 6 || fecha->mes == 9 || fecha->mes == 11)
  4.    {
  5.        if(fecha->dia == 30)
  6.        {
  7.            fecha->dia = 1;
  8.            fecha->mes++;
  9.        }
  10.        else
  11.            fecha->dia++;
  12.    }
  13.    if(fecha->mes == 2)
  14.    {
  15.        if (fecha->año % 4 == 0 && fecha->año % 100 != 0 || fecha->año % 400 == 0)
  16.        {
  17.            if(fecha->dia == 29)
  18.            {
  19.                fecha->dia = 1;
  20.                fecha->mes++;
  21.            }
  22.            else
  23.                fecha->dia++;
  24.        }
  25.        if(fecha->dia == 28)
  26.        {
  27.            fecha->dia = 1;
  28.            fecha->mes++;
  29.        }
  30.        else
  31.            fecha->dia++;
  32.    }
  33.    if(fecha->mes == 1 || fecha->mes == 3 || fecha->mes == 5 || fecha->mes == 7 || fecha->mes == 8 || fecha->mes == 10)
  34.    {
  35.        if(fecha->dia == 31)
  36.        {
  37.            fecha->dia = 1;
  38.            fecha->mes++;
  39.        }
  40.        else
  41.            fecha->dia++;
  42.    }
  43.    if(fecha->mes == 12)
  44.    {
  45.        if(fecha->dia == 31)
  46.        {
  47.            fecha->dia = 1;
  48.            fecha->mes = 1;
  49.            fecha->año++;
  50.        }
  51.        else
  52.            fecha->dia++;
  53.    }
  54. }


Título: Re: Programas para calcular fechas
Publicado por: MAFUS en 24 Mayo 2017, 15:59 pm
De nuevo un error de lógica y parecido al de antes.

Los meses de 30 días están al principio de la función. Cuando los operas pasan a ser meses de 31 días PERO la función no se detiene y llega al código que opera los meses de 31 días. Tu variable ahora es un mes de 31 días y por tanto se le aplica el código de nuevo haciendo que se sume un día.

Tienes 3 formas de solucionar esto:
1. Pones return después de cada operación
2. Haces uso de else if
3. Usas un switch


Título: Re: Programas para calcular fechas
Publicado por: Serapis en 24 Mayo 2017, 17:49 pm
El código es susceptible a errores, porque aunque o tratas bien, lo complicas... cometes el error de querer tratarlo en 'formato humano'....
Abstráete todo lo que puedas del asunto humano, y hazlo desde una perspectiva más matemática...entonces la solución queda sencilla (y el código más breve y legible)

Veamos... los meses son 12, el problema aparecerá pués en los días... que cada mes tiene su tela, icluído los años bisiestos...

Código:
//Entonces creamos un string que represente los meses. Y su contenido sean 12 caracteres
MESES= "@ABCDEFGHIJK" // empiezo en la arroba, si no es tu gusto, cambia como prefieras. En realidad, no lo usamos, se pone solo para que se vea de donde proceden los valores de las dos siguientes variables (sino quedaría oscuro).

//Ahora creamos otras también como string constantes
MesesDe31Dias = "@BDFGIK"  //esto es: enero, marzo, mayo, julio, agosto, octubre, diciembre
MeseeDe30Dias ="CEHJ" // esto es: abril, junio, septiembre, noviembre,
//MesesMenos30 = "A" //esto es, febrero... no se utiliza, se pone por claridad  

Ahora creamos la función: Básicamente simplifica la verificación de los meses y la actualización delos díasy mes, se invoca a otra función.

Código:
Funcion FechaSiguiente(Mes, Dia) boolean  //devolvemos false, si los datos de entrada no están en el rango...
   string M

   Si mes esta en el rango 1-12 luego
       M = (Mes + 63) //porque @ es el ASCII 64, y +63 porque mes está en el rango 1-12, no en rango 0-11
       Si MesesDe30Dias.Contiene(M) luego
           Si Dia esta en el rango 1-30 luego
                llamada FijarMesYDia(Dia, 30, Mes)
                Return TRUE
           Fin si
       Si no
           Si MesesDe31Dias.Contiene(M) luego
               Si Dia esta en el rango 1-31 luego
                   llamada FijarMesYDia(Dia, 31, Mes)
                   Return TRUE
               Fin si    
           Si no // el mes es febrero: porque está en rango y no es ninguno de los anteriores...
               Si Dia es menor de 28 luego
                       Incrementar Dia
               Si no //es día 28 ó 29, falta saber si es bisiesto
                    Si Año no es bisiesto // not ((año mod 4 = 0)   and (año mod 100 <> 0)) //falta la comprobación múltiplo de 400...
                        llamada FijarMesYDia(Dia, 28, Mes)
                    Si no // el año es bisiesto, es día 29?
                        llamada FijarMesYDia(Dia, 29, Mes)                                          
                    Fin si
                    Return TRUE
               Fin si    
           Fin si  
       Fin si
   Fin si
Fin funcion

Funcion FijarMesYDia( Dia, DiaLimite, Mes)
    si Dia < Dialimite luego
         Incrementar Dia
    Si no
        Si Mes < 12 luego   // MesLimite
            Incrementar Mes
        Si no
            Mes = 1
        Fin si
        Dia =1
    Fin si
Fin Funcion

Si necesitas velocidad (no parece quesea el caso, esto no se va allamar miles ni millones devecescadavez, supongo), puedes a la entrada cortar con una comprobación en la que la mayor parte delas veces va a caer, y solo unas pocas veces haría el restode comprobaciones:

Código:
Funcion FechaSiguienteRapido(Mes, Dia) boolean
     Si dia <28 luego
         Incrementar Dia
         Return TRUE
    Si no
        // el resto de veces, deberá comprobar los casos según meses, tal como se hace más arriba, pero solo cuando sean días 28,29,30 y 31
    Fin si
Fin Funcion


Título: Re: Programas para calcular fechas
Publicado por: NicolasPileci en 24 Mayo 2017, 22:04 pm
Muchas gracias a todos!

Un saludo.


Título: Re: Programas para calcular fechas
Publicado por: engel lex en 24 Mayo 2017, 22:33 pm
yo propondría una forma mucho más resumida... sería convertir en dias, calcular y convertir de vuelta

para calcular entre 2 dias
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. const int ajuste[12] = {0,1,-1,0,0,1,1,1,2,2,3,3};
  5.  
  6. typedef struct
  7. {
  8.    int dia,
  9.        mes,
  10.        ano,
  11.        dias_conv;
  12. }   tFecha;
  13.  
  14. int main(){
  15.  tFecha fecha1, fecha2;
  16.  printf("Ingrese dia - Primera fecha: \n\n");
  17.  scanf("%d",&fecha1.dia);
  18.  printf("\nIngrese mes - Primera fecha: \n\n");
  19.  scanf("%d",&fecha1.mes);
  20.  printf("\nIngrese año - Primera fecha: \n\n");
  21.  scanf("%d",&fecha1.ano);
  22.  printf("\nIngrese dia - Segunda fecha: \n\n");
  23.  scanf("%d",&fecha2.dia);
  24.  printf("\nIngrese mes - Segunda fecha: \n\n");
  25.  scanf("%d",&fecha2.mes);
  26.  printf("\nIngrese año - Segunda fecha: \n\n");
  27.  scanf("%d",&fecha2.ano);
  28.  
  29.  fecha1.mes -= 1;
  30.  fecha1.dias_conv = fecha1.ano*365.24 + 30*fecha1.mes + ajuste[fecha1.mes] + fecha1.dia;
  31.  fecha1.mes += 1;
  32.  
  33.  fecha2.mes -= 1;
  34.  fecha2.dias_conv = fecha2.ano*365.24 + 30*fecha2.mes + ajuste[fecha2.mes] + fecha2.dia;
  35.  fecha2.mes += 1;
  36.  
  37.  printf("\ndias entre fechas: %d", fecha2.dias_conv -fecha1.dias_conv );
  38.  return 0;
  39. }
  40.  

da la fecha con erro de 1 dia pero me da pereza depurar


Título: Re: Programas para calcular fechas
Publicado por: MAFUS en 24 Mayo 2017, 22:49 pm
Ala pues. Aquí va el de la fecha del día siguiente:
Código
  1. void obtener_siguiente_fecha(tFecha *fecha) {
  2.    switch(fecha->mes) {
  3.        case 1:
  4.        case 3:
  5.        case 5:
  6.        case 7:
  7.        case 8:
  8.        case 10:
  9.        case 12:
  10.            if(fecha->dia == 31)
  11.                fecha->dia = 0;
  12.            break;
  13.  
  14.        case 4:
  15.        case 6:
  16.        case 9:
  17.        case 11:
  18.            if(fecha->dia == 30)
  19.                fecha->dia = 0;
  20.            break;
  21.  
  22.        case 2:
  23.            if(fecha->dia == 28 + (!(fecha->anyo%4) && fecha->anyo%100) || !(fecha->anyo%400))
  24.                fecha->dia = 0;
  25.            break;
  26.    }
  27.    if(fecha->dia == 0)
  28.        ++fecha->mes;
  29.    if(fecha->mes == 13) {
  30.        fecha->mes = 1;
  31.        ++fecha->anyo;
  32.    }
  33.  
  34.    ++fecha->dia;
  35. }

Evitando que se repita código ;D