C program days between two dates
c
Solution
First, that `leap` function feels overly complicated; you don't need to do both dates in one function call, and I'm sure that can be written more succinctly so that it is more obviously correct. Here's a version I've got laying around that isn't succinct but I'm confident it is easy to check the logic:
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;
}
}
You could call it like this:
int year1, year2, leap1, leap2;
year1 = get_input();
year2 = get_input();
leap1 = is_leap_year(year1);
leap2 = is_leap_year(year2);
No pointers and significantly less code duplication. Yes, I know that `is_leap_year()` can be reduced to a single `if(...)` statement, but this is easy for me to read.
Second, I think you're got a mismatch between 0-indexed arrays and 1-indexed human months:
if(*month1 < 1 || *month1 > 12)
vs
int daysPerMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
Third, I think that days per month can be calculated slightly nicer:
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];
}
Here, I assume January is 0; you would need to force the rest of the code to match. (I learned this double-array trick from The Elements of Programming Style (page 54).) The best part of using a routine like this is that it removes the leap condition from the difference calculation.
Fourth, you're indexing arrays outside their bounds:
for(i = month1 + 1; i <= 12; i++)
{
if(leap1 == 1)
total += daysPerMonthLeap[i];
This is just another instance of the problem with 0-indexed arrays and 1-indexed months -- but be sure that you fix this, too, when you fix the months.
I have a fear that I haven't yet found all the issues -- you may find it easier to sort the first and the second date after input and remove all that validation code -- and then use names `before` and `after` or something to give names that are easier to think through in the complicated core of the calculation.
Problem
I have written a program that should find the days between two dates, but it has some hiccups. The logic makes perfect sense in my head when I read through it, so I'm assuming I have some syntax errors that I keep glancing over or something. Firstly, when entering two dates in different years, the output is always off by about one month (31 in most cases, but 32 in one case...go figure). Second, two dates exactly one month apart will return the number of days in the second month (i.e. 1/1/1 to 2/1/1 yields 28). There are inevitably some other weird things that this program does, but I am hoping that is enough information to help you guys figure out what I'm doing wrong. For the life of me I can't figure this one out on my own. I am relatively new to C, so please be gentle =) Thanks ``` // 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; } } ```