How to check if date is valid using mktime in C? - c

I have a little problem with my code. I need to check if user's given date is valid or not. I want to check it using 2 rules:
1. Date is valid date and found in a calendar (for example 29.2.2015 is invalid because there's only 28 days in February 2015) 2. Day and month can only be max 2 numbers (for example day 10 and 02 are valid but 010 and 002 are not). All help is appreciated!
This is my code this far:
void dateValidator(const char *date1) {
struct tm date = {0};
int day1;
int month1;
int year1;
int vday;
int vmonth;
int vyear;
sscanf(date1, "%3d.%3d.%d",&day1,&month1,&year1);
/**How do I check that if sscanf reads more than 2 characters on month and day, date is
invalid?**/
date.tm_year = year1 - 1900;
date.tm_mon = month1 - 1;
date.tm_mday = day1;
date.tm_isdst = -1;
vday = date.tm_mday;
vmonth = date.tm_mon;
vyear = date.tm_year;
mktime(&pvm);
if ((vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year)) {
/**This doesnt seem to work**/
printf("Invalid date");
}
}

I have deleted my previous answer and posting another one. Actually your code is fine, You just have to send the correct parameter to mktime and to check its return value. I.e. change:
mktime(&pvm);
if ((vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year)) {
/**This doesnt seem to work**/
printf("Invalid date");
}
to something like:
r = mktime(&date);
if (r == -1 || (vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year)) {
printf("Invalid date");
}
and declare the variable r as time_t r;.

int IsValidDate(int year, int month, int day)
{
unsigned int leap;
unsigned char mon_day[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
/* check the rang of the year */
if ((year < 1) || (year >= 3200))
{
return 0;
}
if ((month < 1) || (month > 12))
{
return 0;
}
/* if it's leep year */
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
leap = 1;
}
else
{
leap = 0;
}
mon_day[1] += leap;
if ((day > mon_day[month - 1]) || (day < 1))
{
return 0;
}
return 1;
}
For ruler 1, I have wrote this code for check the date before.
And I hope this code can help you.
The ruler 2 can easily checked, you can check it by format the valid date and compare it with the input string.

How do I check that if sscanf reads more than 2 characters on month and day, date is invalid?
Day and month can only be max 2 numbers digits (for example day 10 and 02 are valid but 010 and 002 are not).
An easy check: Record the offset at the end of the scan and tests 1) that it is not the original 0 (scanning got that far) and 2) this is the end of the string so as to detect extra junk in data1[]. Change 3d to 2d.
int n = 0;
sscanf(date1, "%2d.%2d.%d %n",&day1,&month1,&year1, &n);
if (n > 0 && data1[n] == '\0') Success();
else Fail();
Pedantic code would check with "%[]" to disallow leading spaces and '+'.
int n = 0;
sscanf(date1, "%*2[0-9].%*2[0-9].%*4[0-9] %n", &n);
if (n == 0 || data1[n]) Fail();
else {
sscanf(date1, "%2d.%2d.%d",&day1,&month1,&year1);
...
How to check if date is valid using mktime?
#Marian posted a good solution which adds a test of the return value of mktime().
if (-1 == mktime(&data)) Fail();
if (vday != date.tm_mday) || (vmonth != date.tm_mon) || (vyear != date.tm_year) Fail();

Related

While return loop issue with function call in C

I´m Working on a program for a class and this is what I have so far. My buddy helped me with the function but when a wrong date is entered it should iterate until a correct date is asked. Not sure what to do we have been working on it for a few hours right now and since we are both new to C, we need some outside help.
#include <stdio.h> //for input output
#include <stdlib.h>
#include <string.h> // for string functions
#include <time.h> //for time functions
#include <stdbool.h> //bool functions for true/false
//used typedef for convenience, no need to type struct all the time
typedef struct
{
int m, d, y;
} Data_t;
int checkDate (int m, int d, int y); //declare function to check input
void modDate (Data_t * data); //declare function to modify date
int
main ()
{
int x = 0; //kill switch for while loop
//declare a struct variable and initialize it for the date
Data_t uDate = { 0, 0, 0 };
/* program has infinite loop bug when using the while loop with x */
while (x == 0){
printf ("x before input: %d\n", x); //debug printer
// Ask user for date input
printf ("Enter a date in mm/dd/yyyy format: ");
//Pass the input to the uDate struct with scanf
scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y);
// check data if valid and set x
x = checkDate (uDate.m, uDate.d, uDate.y);
printf ("x after check: %d\n", x); //debug printer
}
// end of while loop
// Display the entered date & modifier message
printf ("\nDate Entered: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
printf ("Adding 1 week to entered date...\n");
modDate (&uDate); //pass the address of uDate to the modDate function
/* since it was passed through a pointer (by reference),
the original uDate struct is now modified */
// Display the modified date
printf ("New Date is: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
return 0;
}
//Define the checkDate function
int
checkDate (int m, int d, int y)
{
// This is sloppy. Clean it up with multiple functions later
if (y <= 0)
{
printf ("Invalid Date, Please try again.\n");
return false;
}
if (m >= 1 && m <= 12)
{
//Then check the days against the months & leap years
if ((d >= 1 && d <= 31)
&& (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10
|| m == 12))
{
return true;
}
else if ((d >= 1 && d <= 30) && (m == 4 || m == 6 || m == 9 || m == 11))
{
return true;
}
else if ((d >= 1 && d <= 28) && (m == 2))
{
return true;
}
else if (d == 29 && m == 2
&& (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)))
{
return true;
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
//Define the modDate function to add 7 days
void
modDate (Data_t * data)
{
data->d = data->d + 7; // modify the day element in struct
// initialize the time_t structs from time.h and pass elements
struct tm t = {.tm_mon = data->m - 1,.tm_mday = data->d,
.tm_year = data->y - 1900
};
/* month+/-1 is because tm struct stores january as 0 and december as 11
year+/- 1900 is because year values are calculated starting from
the year 1900. So when calculating with mktime() you need to get
the integer value of the year by y-1900. And to properly display
the year value that is returned, you add 1900 as done below */
mktime (&t); // call mktime() to calculate the new date
// pass new values into struct and reformat month & year
data->m = t.tm_mon + 1;
data->d = t.tm_mday;
data->y = t.tm_year + 1900;
}
Your problem is that wrong input for scanf is not properly handled.
If you enter something like "A", scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y); won't be successful because it could not read any int that was expected.
Because your "A" is not properly processed it remains in your input buffer what will cause scanf to fail again and again.
So first you should check if all 3 expected values are read:
if (scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y) != 3)
// x remains 0
printf("Invalid input format!\n");
else
x = checkDate (uDate.m, uDate.d, uDate.y);
This alone would not be enough because the wrong input still remains in your input buffer. So you need to flush it before you are making the next try:
Edit
As #AndrewHenle pointed out you should avoid using fflush(stdin) (at least if you are not on a windows platform and want to keep your code portable).
So another solution is to read every input including newline character after user input with e.g. while((getchar()) != '\n');
if (scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y) != 3)
// x remains 0
printf("Invalid input format!\n");
else
x = checkDate (uDate.m, uDate.d, uDate.y);
// flush input buffer
while((getchar()) != '\n');
You have declared return type of int checkDate (int m, int d, int y); as int but return a bool. When correcting this to bool checkDate (int m, int d, int y); the code seems to work:
#include <stdio.h> //for input output
#include <stdlib.h>
#include <string.h> // for string functions
#include <time.h> //for time functions
#include <stdbool.h> //bool functions for true/false
//used typedef for convenience, no need to type struct all the time
typedef struct
{
int m, d, y;
} Data_t;
bool checkDate (int m, int d, int y); //declare function to check input
void modDate (Data_t * data); //declare function to modify date
int
main ()
{
bool x = false; //kill switch for while loop
//declare a struct variable and initialize it for the date
Data_t uDate = { 0, 0, 0 };
/* program has infinite loop bug when using the while loop with x */
while (x == false){
printf ("x before input: %d\n", x); //debug printer
// Ask user for date input
printf ("Enter a date in mm/dd/yyyy format: ");
//Pass the input to the uDate struct with scanf
scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y);
// check data if valid and set x
x = checkDate (uDate.m, uDate.d, uDate.y);
printf ("x after check: %d\n", x); //debug printer
}
// end of while loop
// Display the entered date & modifier message
printf ("\nDate Entered: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
printf ("Adding 1 week to entered date...\n");
modDate (&uDate); //pass the address of uDate to the modDate function
/* since it was passed through a pointer (by reference),
the original uDate struct is now modified */
// Display the modified date
printf ("New Date is: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
return 0;
}
//Define the checkDate function
bool
checkDate (int m, int d, int y)
{
// This is sloppy. Clean it up with multiple functions later
if (y <= 0)
{
printf ("Invalid Date, Please try again.\n");
return false;
}
if (m >= 1 && m <= 12)
{
//Then check the days against the months & leap years
if ((d >= 1 && d <= 31)
&& (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10
|| m == 12))
{
return true;
}
else if ((d >= 1 && d <= 30) && (m == 4 || m == 6 || m == 9 || m == 11))
{
return true;
}
else if ((d >= 1 && d <= 28) && (m == 2))
{
return true;
}
else if (d == 29 && m == 2
&& (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)))
{
return true;
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
//Define the modDate function to add 7 days
void
modDate (Data_t * data)
{
data->d = data->d + 7; // modify the day element in struct
// initialize the time_t structs from time.h and pass elements
struct tm t = {.tm_mon = data->m - 1,.tm_mday = data->d,
.tm_year = data->y - 1900
};
/* month+/-1 is because tm struct stores january as 0 and december as 11
year+/- 1900 is because year values are calculated starting from
the year 1900. So when calculating with mktime() you need to get
the integer value of the year by y-1900. And to properly display
the year value that is returned, you add 1900 as done below */
mktime (&t); // call mktime() to calculate the new date
// pass new values into struct and reformat month & year
data->m = t.tm_mon + 1;
data->d = t.tm_mday;
data->y = t.tm_year + 1900;
}

Validate a date up to current time

i'm doing a program in c that needs to have random dates that have to be valid and after the current date. For the generation there aren't any problems at all. The only thing i can't do is to accept only the up to date dates.
I've already tried to firstly check if the date is valid and then to check if is greater than current date. Then i've tried to do the opposite but any of these solutions didn't worked.
This is the function that checks the date:
short dateControl( const unsigned short day, const unsigned short month, const unsigned short year, const int min_year, const int max_year, struct tm curTime)
{
short correct = ZERO;
if( (year >= curTime.tm_year) && (year <= max_year) ){
if( (month >= 1) && (month <= 12) ){
if( (day >= 1 && day <= 31) && (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) ){
correct = ONE;
}else if( (day >= 1 && day <= 30) && (month == 4 || month == 6 || month == 9 || month == 11) ){
correct = ONE;
}else if( (day >= 1 && day <= 28) && (month == 2) ){
correct = ONE;
}else if( day == 29 && month == 2 && (year % 400 == 0 ||(year % 4 == 0 && year % 100 != 0)) ){
correct = ONE;
}else{
correct = ZERO;
}
} else{
correct = ZERO;
}
}else{
correct = ZERO;
}
if(correct == ONE){
if( year > curTime.tm_year ){
correct = ONE;
}else if( year == curTime.tm_year ){
if( month > curTime.tm_mon ){
correct = ONE;
}else if( month == curTime.tm_mon ){
if( day > curTime.tm_mday ){
correct = ONE;
}else if(day == curTime.tm_mday){
correct = ZERO;
}else if(day < curTime.tm_mday){
correct = ZERO;
}
}else if( month < curTime.tm_mon ){
correct = ZERO;
}
}
}
}
return correct;
}
This is the part where the date is generated
day = random_int(1, 31);
month = random_int(1, 12);
year = random_int(local->tm_year, local->tm_year + 1);
validDate = dateControl(tempTrip.dep_date.day, tempTrip.dep_date.month, tempTrip.dep_date.year, local->tm_year, (local->tm_year + 1), *local);
while(validDate == ZERO){
tempDriver.sub_date.day = random_int(1, 31);
tempDriver.sub_date.month = random_int(1, 12);
tempDriver.sub_date.year = random_int(local->tm_year, (local->tm_year + 1));
validDate = dateControl(tempTrip.dep_date.day, tempTrip.dep_date.month, tempTrip.dep_date.year, local->tm_year, (local->tm_year + 1), *local);
}
}
I expect that if the generated date is 2/7/2019 and today is the 18/8/2019, the generated date needs to be discarded and another needs to be generated.
i'm doing a program in c that needs to have random dates that have to be valid and after the current date. For the generation there aren't any problems at all. The only thing i can't do is to accept only the up to date dates.
The fact that you need to determine if the date is/isn't valid indicates that the way you're generating random dates is a problem.
Specifically, if you get the current time (using time()) and add a random positive value to it (while being careful to avoid overflow), and then convert the result into a date (e.g. using gmtime()); then you can guarantee that the random dates are valid and in the future without doing any checking and you can delete all of your dateControl() code.

C program that reads in a date and prints out the next day date

Hi I have just started learning C language at University. Now I am faced with a problem I just don't know how to solve. So far we have only used
library and nothing else, also scanf is a topic we are going to
learn next week. For now we just use printf for everything.
I have learned how to say if a year is a leap year or not, however, my task is the next one: Need to create a program that reads in a date and prints out the next day date with output like this:
Enter a date in the form day month year: 17 5 2010
The date of the next day is: 18/5/2010
My dilemma is that I have no idea on what operations to use or how to set the code to make sure that leap year is considered and for example if today's date is 28 2 2010 the next date needs to be 1 3 2010 because it wasn't leap year.
The only library used is and there is no scanf yet (with scanf yet)
So far I got this:
#include <stdio.h>
int day, month, year, ndays, leapdays;
bool leapyear;
int main () {
day = 28;
month = 2;
year = 2010;
ndays = day + 1;
leapdays = 31;
leapyear = false;
if (leapyear % 4 == 0) {
leapyear = true;
}
if (leapyear % 100 == 0) {
leapyear = false;
}
if (leapyear % 400 == 0) {
leapyear = true;
}
if ((leapyear) && (month == 12 || month == 1 || month == 3 || month == 5
|| month == 7 || month == 8 || month == 10 )) {
leapdays = 31;
}
if ((leapyear) && (month == 4 || month == 6 || month == 9 || month == 11
)) {
leapdays = 30;
}
if ((leapyear) && (month == 2 )) {
leapdays = 29;
} else if ((leapyear == false) && (month == 2)) {
leapdays = 28;
}
printf ("Enter a date in the form day month year: %d %d %d \n", day,
month, year);
printf ("The date of the next day is: %d/%d/%d", ndays, month, year);
}
Consider a different flow. First find the days per month first, then test if at end of month, and end of year.
int year, month, day;
// set year, month, day in some fashion
day++; // tomorrow
int days_per_month = 31;
if (month == 4 || month == 6 || month == 9 || month == 11) {
days_per_month = 30;
} else if (month == 2) {
days_per_month = 28;
if (year % 4 == 0) {
days_per_month = 29;
if (year % 100 == 0) {
days_per_month = 28;
if (year % 400 == 0) {
days_per_month = 29;
}
}
}
}
if (day > days_per_month) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
Other improvement would use helper functions, enumerated types and various defines. Yet this code seems to reflect OP's level.
Short and simpler. Only check for leap year when needed.
int main()
{
int Iyear, Imonth, Iday;
Iyear = 2016;
Imonth = 4;
Iday = 24;
printf ("Enter a date in the form day month year: %d %d %d \n", Iday, Imonth, Iyear);
NextDate(&Iyear, &Imonth, &Iday);
printf ("The date of the next day is: %d/%d/%d", Iday, Imonth, Iyear);
}
void NextDate(int *year, int *month, int *day)
{
int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
*day = *day +1;
if (( *month == 2 ) && (*day == 29))
{
// Leap year checking, if yes, Feb is 29 days.
if(*year % 400 == 0 || (*year % 100 != 0 && *year % 4 == 0))
{
daysInMonth[1] = 29;
}
}
if (*day > daysInMonth[*month -1])
{
*day = 1;
*month = *month +1;
if (*month > 12)
{
*month = 1;
*year = *year +1;
}
}
}
After you add 1 to the day, check to see if that value is greater than the number of days in that month. If so, set the day to 1 and add 1 to the month. Then check if month is greater than 12, and if so set the month to 1 and add 1 to the year.
As for determining the number of days in a month, all months except February have the same number of days whether or not the year is a leap year. Right now you're checking if the year is a leap year for those other months. You can leave that check out and just check the month number.
if (month == 12 || month == 1 || month == 3 || month == 5
|| month == 7 || month == 8 || month == 10 ) {
leapdays = 31;
}
if (month == 4 || month == 6 || month == 9 || month == 11) {
leapdays = 30;
}
Got it right :) thanks for all the help
#include <stdio.h>
int day, month, year, ndays, leapdays;
bool leapyear;
int main () {
day = 31;
month = 12;
year = 2010;
ndays = day + 1;
leapyear = false;
printf ("Enter a date in the form day month year: %d %d %d \n", day, month, year);
if (year % 4 == 0) {
leapyear = true;
}
if (year % 100 == 0) {
leapyear = false;
}
if (year % 400 == 0) {
leapyear = true;
}
if ((leapyear) && (month == 12 || month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 )) {
leapdays = 31;
}
if ((leapyear) && (month == 4 || month == 6 || month == 9 || month == 11 )) {
leapdays = 30;
}
if ((leapyear) && (month == 2 )) {
leapdays = 29;
} else if (leapyear == false) {
leapdays = 28;
}
if ((leapdays == 31) && (day == 31)) {
ndays = 1;
month = month + 1;
}else if ((leapdays == 30) && (day == 30)) {
ndays = 1;
month = month + 1;
}else if ((leapdays == 29) && (day == 29)) {
ndays = 1;
month = month + 1;
}else if ((leapdays == 28) && (day == 28)) {
ndays = 1;
month = month + 1;
}else if ((month == 12) && (day == 31)) {
ndays = 1;
month = 1;
year = year + 1;
}
printf ("The date of the next day is: %d/%d/%d", ndays, month, year);
}

Test Function Not Working C Programming

I am attempting to write code that checks the validity of a date [day and month only], inputs that date [day and month] into a "Date" structure, and then, finally, checks that the code in fact did what I expected it to do in a test function, by printing "SUCCESS" if successful, or "FAILURE" if not;
I have tried everything, and cannot think of what the problem might be; I am getting no warnings, so debugger didnt help. the code compiles and runs, however, there is nothing being printed on screen to let me know if it is actually working or not;
Any feedback would be greatly appreciated, thank you!
#include <stdio.h>
#include <stdlib.h>
#include "PatientData.h"
#define INVALID -100
#define SUCCESS 0
int main()
{
int datechecker(int month, int day) {
int ret = SUCCESS;
month = 2;
day = 2;
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8
|| month == 10 || month == 12)
{
if(!(day >= 1 && day <= 31))
ret = INVALID;
}
else if (month == 4 || month == 6 || month == 9 || month == 11)
{
if(!(day >= 1 && day < 31 ))
ret = INVALID;
}
else
{
ret = INVALID;
}
return(ret);
}
Date CreateDate(int day, int month)
{
Date date;
int ret = datechecker(2,2);
if (ret == SUCCESS)
{
date.Day = day;
date.Month = month;
}
else
{
date.Day = INVALID;
}
return date;
}
void CreateDateTest ()
{
Date date = CreateDate(2,2);
if (date.Day == 2)
{
printf("PASSED");
}
else
{
printf("FAILED");
}
}
return 0;
}
Well, you have three functions defined inside main, called CreateDate, CreateDateTest, and datechecker. However, the lone executable statement inside main is return 0, which is what your program is faithfully doing.
Your code cannot be run as such since PatientData.h is not available, but I suspect it will work once you call CreateDateTest from main.

C program days between two dates

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;
}
}
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.
This is not a complete answer. I just wanted to mention a better way to calculate leap year (this is taken from The C Programming Language - Page #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);
Reduce all month indexes by 1.
What I mean to say is January will correspond to daysPerMonth[0] or daysPerMonthLeap[0] and not daysPerMonth[1] or daysPerMonthLeap[1].
The reason for this being array indexes start from 0.
So, wherever you are using month1, month2 insidedaysPerMonth[] or daysPerMonthLeap[], use month1-1 and month2-1 instead.
I hope this is clear enough.
Otherwise, feel free to comment.
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};
to
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};
i.e. pad the arrays at the beginning since all the code relies on the array values to start at element 1 rather than element 0.
That will get rid of the error you complained of.
The other problem is an off-by-one error when you add day2 to the total. In both cases you should add day2 - 1 rather than day2. This is also due to the date indexes starting at 1 instead of 0.
After I made these changes (plus a couple just to get the code to compile), it works properly.
There are multiple problems in your code snippet.. but I must say it is a very good attempt. There are many short cuts to what you're try to achieve.
I have written the following program which finds the number of days between two given dates. You may use this as a reference.
#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;
}
The output is as follows:
$ gcc dates.c
$ ./a.out
30 June 2006
28 Oct 2018
number of days: 4503
$
Note: this is not a complete program. It lacks input validation.
Hope it helps!
//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;
}

Resources