2012-04-25 20 views
6

Ho scritto un programma che dovrebbe trovare i giorni tra due date, ma ha alcuni singhiozzo. La logica ha perfettamente senso nella mia testa quando la leggo, quindi presumo di avere alcuni errori di sintassi su cui continuo a dare un'occhiata o qualcosa del genere.C giorni di programma tra due date

In primo luogo, quando si immettono due date in anni diversi, l'output è sempre disattivato di circa un mese (31 nella maggior parte dei casi, ma 32 in un caso ... vai alla figura). In secondo luogo, due date esattamente a distanza di un mese restituiranno il numero di giorni nel secondo mese (cioè il rendimento da 1/1/1 a 2/1/1 28). Ci sono inevitabilmente altre strane cose che questo programma fa, ma spero che siano sufficienti informazioni per aiutarti a capire cosa sto facendo male. Per la vita di me non riesco a capire questo da solo. Sono relativamente nuovo a C, quindi si prega di essere gentile =)

Grazie

// Calculates the number of calendar days between any two dates in history (beginning with 1/1/1). 

#include <stdio.h> 
#include <stdlib.h> 

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 < 1 || *month1 > 12) 
       { 
         printf("Invalid entry for month.\n"); 
         fail += 1; 
       } 
       if(*day1 < 1 || *day1 > 31) 
       { 
         printf("Invalid entry for day.\n"); 
         fail += 1; 
       } 
       if(*year1 < 1) 
       { 
         printf("Invalid entry for year.\n"); 
         fail += 1; 
       } 
       if(daysPerMonth[month1] == 30 && *day1 > 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 < 1 || *month2 > 12) 
       { 
         printf("Invalid entry for month.\n"); 
         fail += 1; 
       } 
       if(*day2 < 1 || *day2 > 31) 
       { 
         printf("Invalid entry for day.\n"); 
         fail += 1; 
       } 
       if(*year2 < 1) 
       { 
         printf("Invalid entry for year.\n"); 
         fail += 1; 
       } 
       if(daysPerMonth[month2] == 30 && *day2 > 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; 
     } 
} 
+0

non esiste una libreria per questo? – mkoryak

+0

@mkoryak, probabilmente, questo è un problema di apprendimento abbastanza discreto ... – sarnold

+0

Per month1 = 1, è quello gennaio o febbraio nel codice (basato sulla matrice daysPerMonth)? Penso che questo sia uno dei problemi nel tuo codice. Il codice antepone un elemento = 0 in entrambi gli array o riduce il mese di 1 mentre si eseguono i calcoli. – spicavigo

risposta

3

ridurre tutti gli indici mese di 1.

Quello che intendo dire è gennaio sarà conforme a daysPerMonth[0] o daysPerMonthLeap[0] e non daysPerMonth[1] o daysPerMonthLeap[1]. La ragione di questo è indici di matrice inizia da 0.

Così, ovunque si utilizza month1, month2 all'interno daysPerMonth[] o daysPerMonthLeap[], utilizzare month1-1 e month2-1 invece.

Spero che questo sia abbastanza chiaro. Altrimenti, sentiti libero di commentare.

+0

Yup, haha. Risolto questo problema e funziona magnificamente. = D – Andbrik

+0

@Andbrik, ti ​​piacerebbe condividere il tuo codice finale? – bob90937

6

Innanzitutto, la funzione leap risulta eccessivamente complicata; non è necessario eseguire entrambe le date in una chiamata di funzione e sono sicuro che può essere scritto in modo più sintetico in modo che sia più corretto. Ecco una versione che ho ottenuto, che in giro che non è succinta ma sono fiducioso è facile controllare la logica:

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; 
     } 
} 

Si può chiamare in questo modo:

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

Nessun puntatore e molto meno duplicazione del codice. Sì, so che lo is_leap_year() può essere ridotto a una singola dichiarazione if(...), ma per me è facile da leggere.

In secondo luogo, credo che tu stia ottenuto una mancata corrispondenza tra 0-indicizzati array e 1-indicizzati mesi umani:

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

vs

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

In terzo luogo, penso che giorni al mese può essere calcolato leggermente più bello:

int days_in_month(int month, int year) { 
     int leap = is_leap_year(year); 
     /*    J F M A M J J A S O N D */ 
     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]; 
} 

Qui, presumo che gennaio sia 0; avresti bisogno di forzare il resto del codice per far combaciare. (Ho imparato questo trucco a doppia fila da The Elements of Programming Style (page 54).) La parte migliore dell'utilizzo di una routine come questa è che rimuove la condizione di salto dal calcolo della differenza.

In quarto luogo, si sta l'indicizzazione array di fuori dei loro confini:

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

Questo è solo un altro esempio del problema con 0-indicizzati array e mesi 1-indicizzati - ma essere sicuri che ti fissano questo, anche quando correggi i mesi.

Ho una paura che non ho ancora trovato tutti i problemi - si può trovare più facile sorta la prima e la seconda data dopo di ingresso e rimuovere tutto ciò che il codice di convalida - e quindi utilizzare nomi before e after o qualcosa per dare nomi più facili da pensare nel nucleo complesso del calcolo.

+0

Simpatico riferimento allo stile - consiglieresti anche di eliminare il blocco "se" separato per gli anni in cui gli anni sono uguali? La soluzione generale dovrebbe gestire questo caso – nvuono

+0

Grazie per l'aiuto. Si scopre che l'indicizzazione del mio array è stata l'unica cosa che mi ha incasinato * facepalm *. Funziona alla grande ora! – Andbrik

+0

@Andbrik: sebbene l'indice dell'array fosse l'unico problema, prendi in considerazione i suggerimenti di sarnold per rendere il tuo programma efficiente e breve. – tumchaaditya

3

Questa non è una risposta completa. Volevo solo parlare di un modo migliore per calcolare anno bisestile (questo è preso da The C Programming Language - Pagina n ° 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); 
2

Change

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}; 

cioè pad gli array all'inizio poiché tutto il codice si basa sui valori dell'array per iniziare dall'elemento 1 anziché dall'elemento 0.

Questo eliminerà l'errore lamentato.

L'altro problema è un errore di off-by-one quando si aggiunge day2 al totale. In entrambi i casi è necessario aggiungere day2 - 1 anziché day2. Ciò è dovuto anche agli indici di data che iniziano da 1 invece di 0.

Dopo aver apportato queste modifiche (più una coppia solo per ottenere il codice da compilare), funziona correttamente.

+0

about day2 & day2-1 thing: day2-1 darà giorni TRA quelle 2 date (entrambe escluse). Ma, quando di solito calcoliamo i giorni tra 2 date, è consuetudine includere un giorno. ad es. La differenza tra il 4 maggio e il 1 ° maggio è di 3 giorni ... non 2 giorni ... – tumchaaditya

+0

Questo è il caso "day2 - day1', dove i giorni sono nello stesso mese. I due compiti da modificare sono quelli in cui day2 viene aggiunto senza che il giorno 1 venga sottratto da esso. –

+0

Grazie, mi stava dando un mal di testa lol. – Andbrik

1

Ci sono diversi problemi nello snippet di codice .. ma devo dire che è un ottimo tentativo. Ci sono molte scorciatoie per quello che stai cercando di ottenere.

Ho scritto il seguente programma che trova il numero di giorni tra due date date. Puoi usare questo come riferimento.

#include <stdio.h> 
#include <stdlib.h> 

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; 
} 

L'uscita è la seguente:

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

Nota: questo non è un programma completo. Manca la convalida dell'input.

Spero che aiuti!

+0

È possibile utilizzare http://www.timeanddate.com/date/duration.html per convalidare i risultati. –

0
//Difference/Duration between two dates 
//No need to calculate leap year offset or anything 
// Author: Vinay Kaple 
# include <iostream> 
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: "<<total_days<<"\n"; 
    int total_seconds = total_days*24*60*60; 
    cout<<"Total seconds: "<<total_seconds<<"\n"; 
    return 0; 
} 
+0

Si prega di condividere alcune informazioni sul frammento di codice di appena incollare il codice. – gmuraleekrishna

Problemi correlati