Progtwig de días C entre dos fechas.

He escrito un progtwig que debería encontrar los días entre dos fechas, pero tiene algunos contratiempos. La lógica tiene mucho sentido en mi cabeza cuando la leo, así que asumo que tengo algunos errores de syntax que sigo echando un vistazo o algo así.

En primer lugar, cuando se ingresan dos fechas en años diferentes, la salida siempre se desactiva alrededor de un mes (31 en la mayoría de los casos, pero 32 en un caso … imagínese). En segundo lugar, dos fechas con un mes de diferencia devolverán el número de días del segundo mes (es decir, 1/1/1 a 2/1/1, rendimientos 28). Inevitablemente, hay otras cosas extrañas que hace este progtwig, pero espero que sea suficiente información para ayudarlos a descubrir qué estoy haciendo mal. Por mi vida no puedo resolver esto por mi cuenta. Soy relativamente nuevo en C, así que por favor sea amable =)

Gracias

// Calculates the number of calendar days between any two dates in history (beginning with 1/1/1). #include  #include  void leap(int year1, int year2, int *leap1, int *leap2); void date(int *month1, int *day1, int *year1, int *month2, int *day2, int *year2, int *leap1, int *leap2); int main(void) { int month1, day1, year1, month2, day2, year2, leap1, leap2; int daysPerMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; int daysPerMonthLeap[] = {31,29,31,30,31,30,31,31,30,31,30,31}; leap(year1, year2, &leap1, &leap2); date(&month1, &day1, &year1, &month2, &day2, &year2, &leap1, &leap2); if(year1 == year2) { int i, total; if(month1 == month2) // Total days if month1 == month2 { total = day2 - day1; printf("There are %d days between the two dates.", total); } else { if(leap1 == 1) total = daysPerMonthLeap[month1] - day1; else total = daysPerMonth[month1] - day1; for(i = month1 + 1; i < month2; i++) // Days remaining between dates (excluding last month) { if(leap1 == 1) total += daysPerMonthLeap[i]; else total += daysPerMonth[i]; } total += day2; // Final sum of days between dates (including last month) printf("There are %d days between the two dates.", total); } } else // If year1 != year2 ... { int i, total, century1 = ((year1 / 100) + 1) * 100, falseleap = 0; if(leap1 == 1) total = daysPerMonthLeap[month1] - day1; else total = daysPerMonth[month1] - day1; for(i = month1 + 1; i <= 12; i++) // Day remaining in first year { if(leap1 == 1) total += daysPerMonthLeap[i]; else total += daysPerMonth[i]; } for(i = 1; i < month2; i++) // Days remaining in final year (excluding last month) { if(leap2 == 1) total += daysPerMonthLeap[i]; else total += daysPerMonth[i]; } int leapcount1 = year1 / 4; // Leap years prior to and including first year int leapcount2 = year2 / 4; // Leap years prior to and NOT including final year if(year2 % 4 == 0) leapcount2 -= 1; int leaptotal = leapcount2 - leapcount1; // Leap years between dates for(i = century1; i < year2; i += 100) // "False" leap years (divisible by 100 but not 400) { if((i % 400) != 0) falseleap += 1; } total += 365 * (year2 - year1 - 1) + day2 + leaptotal - falseleap; // Final calculation printf("There are %d days between the two dates.", total); } return 0; } void leap(int year1, int year2, int *leap1, int *leap2) // Determines if first and final years are leap years { if(year1 % 4 == 0) { if(year1 % 100 == 0) { if(year1 % 400 == 0) *leap1 = 1; else *leap1 = 0; } else *leap1 = 1; } else *leap1 = 0; if(year2 % 4 == 0) { if(year2 % 100 == 0) { if(year2 % 400 == 0) *leap2 = 1; else *leap2 = 0; } else *leap2 = 1; } else *leap2 = 0; } void date(int *month1, int *day1, int *year1, int *month2, int *day2, int *year2, int *leap1, int *leap2) { for(;;) // Infinite loop (exited upon valid input) { int fail = 0; printf("\nEnter first date: "); scanf("%d/%d/%d", month1, day1, year1); if(*month1  12) { printf("Invalid entry for month.\n"); fail += 1; } if(*day1  31) { printf("Invalid entry for day.\n"); fail += 1; } if(*year1  30) { printf("Invalid month and day combination.\n"); fail += 1; } if(*month1 == 2) { if(*leap1 == 1 && *day1 > 29) { printf("Invalid month and day combination.\n"); fail += 1; } else if(*day1 > 28) { printf("Invalid month and day combination.\n"); fail += 1; } } if(fail > 0) continue; else break; } for(;;) { int fail = 0; printf("\nEnter second date: "); scanf("%d/%d/%d", month2, day2, year2); if(*year1 == *year2) { if(*month1 > *month2) { printf("Invalid entry.\n"); fail += 1; } if(*month1 == *month2 && *day1 > *day2) { printf("Invalid entry.\n"); fail += 1; } } if(*month2  12) { printf("Invalid entry for month.\n"); fail += 1; } if(*day2  31) { printf("Invalid entry for day.\n"); fail += 1; } if(*year2  30) { printf("Invalid month and day combination.\n"); fail += 1; } if(*month2 == 2) { if(*leap2 == 1 && *day2 > 29) { printf("Invalid month and day combination.\n"); fail += 1; } else if(*day2 > 28) { printf("Invalid month and day combination.\n"); fail += 1; } } if(fail > 0) continue; else break; } } 

Primero, esa función de leap siente demasiado complicada; no necesita hacer ambas fechas en una llamada de función, y estoy seguro de que puede escribirse de manera más sucinta para que sea más obviamente correcto. Aquí hay una versión que tengo que no es sucinta pero estoy seguro de que es fácil verificar la lógica:

 int is_leap_year(int year) { if (year % 400 == 0) { return 1; } else if (year % 100 == 0) { return 0; } else if (year % 4 == 0) { return 1; } else { return 0; } } 

Podrías llamarlo así:

 int year1, year2, leap1, leap2; year1 = get_input(); year2 = get_input(); leap1 = is_leap_year(year1); leap2 = is_leap_year(year2); 

Sin punteros y significativamente menos duplicación de código. Sí, sé que is_leap_year() se puede reducir a una sola sentencia if(...) , pero para mí es fácil de leer.

En segundo lugar, creo que tienes un desajuste entre los arrays indexados 0 y los meses humanos indexados 1:

  if(*month1 < 1 || *month1 > 12) 

vs

  int daysPerMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; 

En tercer lugar, creo que los días por mes se pueden calcular un poco mejor:

 int days_in_month(int month, int year) { int leap = is_leap_year(year); /* JFMAMJJASOND */ int days[2][12] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; if (month < 0 || month > 11 || year < 1753) return -1; return days[leap][month]; } 

Aquí, supongo que enero es 0; necesitarías forzar el rest del código para que coincida. (Aprendí este truco de doble matriz de The Elements of Programming Style ( página 54 ).) Lo mejor de usar una rutina como esta es que elimina la condición de salto del cálculo de la diferencia.

Cuarto, estás indexando matrices fuera de sus límites:

  for(i = month1 + 1; i <= 12; i++) { if(leap1 == 1) total += daysPerMonthLeap[i]; 

Esta es solo otra instancia del problema con las matrices indexadas 0 y los meses indexados 1, pero asegúrese de corregir esto también cuando arregle los meses.

Me temo que todavía no he encontrado todos los problemas; puede que te resulte más fácil ordenar la primera y la segunda fecha después de ingresar y eliminar todo ese código de validación, y luego usar nombres before y after o algo para dar. Nombres que son más fáciles de pensar en el complicado núcleo del cálculo.

Esta no es una respuesta completa. Solo quería mencionar una mejor manera de calcular el año bisiesto (esto está tomado de The C Programming Language – Página # 41)

 if ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0) printf("%d is a leap year \n", year); else printf("%d is not a leap year \n", year); 

Reducir todos los índices de mes en 1.

Lo que quiero decir es que enero corresponderá a daysPerMonth[0] o daysPerMonthLeap[0] y no a daysPerMonth[1] o daysPerMonthLeap[1] . La razón de que esto sea que los índices de matriz comienzan desde 0.

Entonces, donde sea que estés usando month1 , month2 dentro de daysPerMonth[] o daysPerMonthLeap[] , usa month1-1 y month2-1 en month2-1 lugar.

Espero que esto sea lo suficientemente claro. De lo contrario, no dude en comentar.

Cambio

 int daysPerMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31}; int daysPerMonthLeap[] = {31,29,31,30,31,30,31,31,30,31,30,31}; 

a

 int daysPerMonth[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; int daysPerMonthLeap[] = {0,31,29,31,30,31,30,31,31,30,31,30,31}; 

es decir, rellene las matrices al principio, ya que todo el código se basa en los valores de la matriz para comenzar en el elemento 1 en lugar del elemento 0.

Eso te librará del error del que te quejaste.

El otro problema es un error off-by-one cuando agrega day2 al total. En ambos casos, debe agregar day2 - 1 lugar de day2 . Esto también se debe a los índices de fecha que comienzan en 1 en lugar de 0.

Después de realizar estos cambios (más un par solo para comstackr el código), funciona correctamente.

Hay varios problemas en su fragmento de código … pero debo decir que es un muy buen bash. Hay muchos atajos a lo que intentas lograr.

He escrito el siguiente progtwig que encuentra el número de días entre dos fechas determinadas. Puedes usar esto como referencia.

 #include  #include  char *month[13] = {"None", "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"}; /* daysPerMonth[0] = non leap year daysPerMonth[1] = leap year */ int daysPerMonth[2][13] = {{-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; typedef struct _d { int day; /* 1 to 31 */ int month; /* 1 to 12 */ int year; /* any */ }dt; void print_dt(dt d) { printf("%d %s %d \n", d.day, month[d.month], d.year); return; } int leap(int year) { return ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0) ? 1 : 0; } int minus(dt d1, dt d2) { int d1_l = leap(d1.year), d2_l = leap(d2.year); int y, m; int total_days = 0; for (y = d1.year; y >= d2.year ; y--) { if (y == d1.year) { for (m = d1.month ; m >= 1 ; m--) { if (m == d1.month) total_days += d1.day; else total_days += daysPerMonth[leap(y)][m]; // printf("%d - %5s - %d - %d \n", y, month[m], daysPerMonth[leap(y)][m], total_days); } } else if (y == d2.year) { for (m = 12 ; m >= d2.month ; m--) { if (m == d2.month) total_days += daysPerMonth[leap(y)][m] - d2.day; else total_days += daysPerMonth[leap(y)][m]; // printf("%d - %5s - %d - %d \n", y, month[m], daysPerMonth[leap(y)][m], total_days); } } else { for (m = 12 ; m >= 1 ; m--) { total_days += daysPerMonth[leap(y)][m]; // printf("%d - %5s - %d - %d \n", y, month[m], daysPerMonth[leap(y)][m], total_days); } } } return total_days; } int main(void) { /* 28 Oct 2018 */ dt d2 = {28, 10, 2018}; /* 30 June 2006 */ dt d1 = {30, 6, 2006}; int days; int d1_pt = 0, d2_pt = 0; if (d1.year > d2.year) d1_pt += 100; else d2_pt += 100; if (d1.month > d2.month) d1_pt += 10; else d2_pt += 10; if (d1.day > d2.day) d1_pt += 1; else d2_pt += 1; days = (d1_pt > d2_pt) ? minus(d1, d2) : minus(d2, d1); print_dt(d1); print_dt(d2); printf("number of days: %d \n", days); return 0; } 

La salida es la siguiente:

 $ gcc dates.c $ ./a.out 30 June 2006 28 Oct 2018 number of days: 4503 $ 

Nota: este no es un progtwig completo. Carece de validación de entrada.

¡Espero eso ayude!

 //Difference/Duration between two dates //No need to calculate leap year offset or anything // Author: Vinay Kaple # include  using namespace std; int main(int argc, char const *argv[]) { int days_add, days_sub, c_date, c_month, b_date, b_month, c_year, b_year; cout<<"Current Date(dd mm yyyy): "; cin>>c_date>>c_month>>c_year; cout<<"Birth Date(dd mm yyyy): "; cin>>b_date>>b_month>>b_year; int offset_month[12] = {0,31,59,90,120,151,181,212,243,273,304,334}; days_add = c_date + offset_month[c_month-1]; days_sub = b_date + offset_month[b_month-1]; int total_days = (c_year-b_year)*365.2422 + days_add - days_sub+1; cout<<"Total days: "<