Help with Date Validation

Apr 3, 2012 at 7:47pm
I'm writing a program for school that I am asked to get a user to enter a date and my program is to validate the date, show the date they entered if valid, and ask if they would like to repeat the process. All this is using oop C++.
I think everything is working without error except it doesn't seem to be validating. Any help would be appreciated, I'm pretty new at this. Code follows.

Header file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef Date_H
#define Date_H

#include <iostream>

/*********Class Date Specification**********/

class Date
{
private:
	int month;
	int day;
	int year;	

public:
	Date();
	Date(int, int, int);
	
	//mutator functions
	void setDate(int, int, int);
	void showDate();
	void getDate(int, int, int);

	//accessor functions
	bool CheckDate(int, int, int);
	bool isLeap(int year);
};
#endif 


Implementation file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include "Date.h"
using namespace std;


//  default constructor
Date::Date()
{
   setDate(1, 1, 2000);
}

//  constructor that initializes all data members
Date::Date(int mo, int da, int yr)
{
   month = mo;
   day = da;
   year = yr;
}


void Date::setDate(int mo, int da, int yr)
{
   month = mo;
   day = da;
   year = yr;
}

//get the date
void Date::getDate(int, int, int)
{
	cout << "Enter Month: ";
		cin >> month;
		cout << endl;
		cout << "Enter Day: ";
		cin >> day;
		cout << endl;
		cout << "Enter Year: ";
		cin >> year;
		cout << endl;
		
}


//  print the invoking object in the format mm/dd/yyyy
void Date::showDate()
{
   cout << month << '/' << day << '/' << year;
}

//test to validate date - calls isLeap
bool Date::CheckDate(int month, int day, int year)
{
    bool result = true;
    int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(year<1850||year>2100)
		result = false;
	if (isLeap(year))
    {
        daysInMonths[1] = 29;   // Feb has 29 days in leap year
    }
    if (month < 1 || month > 12)
    {
        result = false;
    }
    else if (day < 1 || day > daysInMonths[month-1])
    {
        result = false;
    }
    return result;


Main File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
using namespace std;
#include "Date.h"

int main()
{
	int month, day, year;
	char choice;
	do
	{
		Date userInput(month =1, day =1, year =2003);

		userInput.getDate(month, day, year);

		userInput.CheckDate(month, day, year);
		
	//display the date
	cout <<"The date you entered is: ";
	userInput.showDate();
	
	cout << "\nWould you like to enter another date?(Y/N)" << endl;
      cin >> choice;
	}
      while(choice != 'n' && choice != 'N');
	
}
Apr 3, 2012 at 7:54pm
what is the problem you are getting exactly? you say its not checkingdate properly?

Apr 3, 2012 at 8:05pm
Yup. I am not getting any compiling errors, but if I enter a date that should be invalid, say 13/32/2012, it just passes it through instead of throwing an error. I think my validation functions are correct but I'm not sure that I am calling them correctly. Only a guess as I'm not real proficient at this coding thing yet.
Apr 3, 2012 at 8:08pm
do validation in your constructor, pass the variables from there to validate if its true or not

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Date::Date(int mo, int da, int yr)
{
  if(CheckDate(int month, int day, int year)){
   month = mo;
   day = da;
   year = yr;
}
  else
{
   cout << "error" << endl;
   month = 1;
   day = 1;
   year = 2012;
}
}
Last edited on Apr 3, 2012 at 8:08pm
Apr 3, 2012 at 8:53pm
You are making a couple mistakes that is confusing you.

There are, at any one time, more than one variable named "month":

- Your program as a variable named "month" in main(), which we might call "main.month".

- It has another variable named month declared in your Date object, which is itself declared in main, so we might call it "main.userInput.month".

- There are other variables declared as arguments to some of the functions, such as "userInput.CheckDate(month,...)".

(The same is true for "day" and "year".)


The error is that you are confusing all these things. Sometimes you use main's "month". Sometimes you use userInput's "month". Sometimes you use arguments (and sometimes you ignore them). This is where you are failing.

(Am I correct in assuming that no matter what date you enter it always validates as OK?)

______________________________

Before going any further, let's fix a couple of errors with the class's design.

The "Date" class itself is supposed to handle a month, day, and year. All other instances of variables named "month", "day", and "year" should only be temporary -- we are only interested in a Date's month, day, and year.

The next thing is that getX() and setX() methods are not supposed to be doing any I/O -- all they should do is get or set a Date's month, day, and year values. (I don't know how much detail your professor has taken you to yet, but the setX() method should also make sure that the Date does not have invalid values for month, day, and year.)

So, let's rewrite that header a little bit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef Date_H
#define Date_H

#include <iostream>

/*********Class Date Specification**********/

class Date
{
private:
	int month;
	int day;
	int year;	

public:
	Date();
	Date(int m, int d, int y);  // Make sure to give the arguments NAMES
	
	//mutator methods == methods that CHANGE the object
	void setDate(int m, int d, int y);

	//accessor methods == methods that OBSERVE the object
	void getDate(int& m, int& d, int& y) const;  // WHAT ARE the object's current m,d,y values?

	//I/O methods == methods that perform I/O
	void showDate() const;  // this prints to the console, apparenty
	// (You could, conceivably, add a method that reads a date from the console -- something like readDate();.)

	//information and validation functions - these work on ARGUMENTS and do nothing else
	bool isLeap(int y) const;  // is the ARGUMENT y a leap year?
	bool CheckDate(int m, int d, int y) const;  // is the ARGUMENT date m,d,y a valid date?
};
#endif  

(The "const" stuff says that a specific method does not change a Date object. Only the mutator methods do that.)

Notice also how getDate() should not do any I/O? All it does is allow you to find out what the Date's current month, day, and year are. For example, I can find out what the default month is this way:

1
2
3
4
	Date default_date;
	int month,d,y;
	default_date.getDate(month,d,y);
	cout << "The default month is: " << month << endl;

(It should say "1" because the default constructor sets the date to 1,1,2000 on line 9 of "Date.cpp".)

If I want to have the user input a date, I currently need to do it myself:

1
2
3
4
5
	Date user_date;
	int mo,day,yr;
	cout << "Enter the date as, for example, 2 28 2003: ";
	cin >> mo >> day >> yr;
	user_date.setDate(mo,day,yr);

______________________________

Remember that I said that the date should be automatically validated? This should be done in two spots, both of which are when someone sets the Date's month, day, and year:

- the non-default constructor (the one taking arguments)
- the setDate() method
- the readDate() method if you create it

If the new date is invalid then the date should not be changed. For example:

1
2
3
4
5
6
7
8
9
10
11
int main()
{
	Date fooey( 72, -4, 4013 );
	fooey.showDate();

	Date good( 7, 4, 2012 );
	good.showDate();

	good.setDate( -7, 512, 32 );
	good.showDate();
}
% ./a.out
1/1/2000
7/4/2012
7/4/2012
%

Notice that the first date that printed was the default date value -- since we tried to create a date with an invalid value. The date constructor refused to let us do that.

The second date was OK, so the constructor let us do that without any problems.

We then tried to set the good date to something bad, but the setDate() method didn't let us do that, so the next time we print it we see that the date was not allowed to be changed.

Here is how the constructor makes sure that it is OK:

1
2
3
4
5
6
7
8
9
Date::Date(int m, int d, int y)
{
	if (CheckDate(m,d,y))
	{
		month = m;
		day = d;
		year = y;
	}
}

The setDate() function should work very much the same.

The getDate() function has reference arguments:

1
2
3
4
5
void getDate(int& m, int& d, int& y) const
{
	m = month;
	...
}

Make sense?


______________________________

You did not post your IsLeapYear() method, but I presume it uses the standard formula?

Also, I am not sure what is wrong with dates before 1850...

Hope this helps.
Apr 3, 2012 at 8:59pm
Thanks. I've implemented your suggestion (see code below(only implementation file)) It still doesn't seem to be checking the date for errors. Along with that I know see in my output in console first line "error", which is from the else statement. Any further ideas?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include "Date.h"
using namespace std;


//  default constructor
Date::Date()
{
   setDate(1, 1, 2000);
}

//  constructor that initializes all data members
Date::Date(int mo, int da, int yr)
{
  if(CheckDate(month, day, year))
  {
   month = mo;
   day = da;
   year = yr;
  }
  else
  {
   cout << "error" << endl;
   month = 1;
   day = 1;
   year = 2012;
  }
}


void Date::setDate(int mo, int da, int yr)
{
   month = mo;
   day = da;
   year = yr;
}

//get the date
void Date::getDate(int mo, int da, int yr)
{
	cout << "Enter Month: ";
		cin >> month;
		cout << endl;
		cout << "Enter Day: ";
		cin >> day;
		cout << endl;
		cout << "Enter Year: ";
		cin >> year;
		cout << endl;
		
}


//  print the invoking object in the format mm/dd/yyyy
void Date::showDate()
{
   cout << month << '/' << day << '/' << year;
}

//test to validate date - calls isLeap
bool Date::CheckDate(int month, int day, int year)
{
    bool result = true;
    int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(year<1850||year>2100)
		result = false;
	if (isLeap(year))
    {
        daysInMonths[1] = 29;   // Feb has 29 days in leap year
    }
    if (month < 1 || month > 12)
    {
        result = false;
    }
Apr 3, 2012 at 9:04pm
it is checking for them in the if statement, if any of them return false from the CheckDate() function, it will indeed produce the error message
Apr 3, 2012 at 9:23pm
@Duoas - Thanks for all the time you must have spent on this. I'm at work now but I'll try to digest what you have answered and make some changes.

To answer your questions - 1850 was the professors assigned cut off date.

code for isLeap follows. Not sure how I left that out.
1
2
3
4
5
6
7
8
//test for leap year
bool Date::isLeap(int year)
    {
    if (year%4==0 && year%100!=0 || year%400==0)
        return true;
    else
        return false;
	}
Apr 4, 2012 at 2:01am
So I have made some changes and used Duoas's header file given above. I've been able to compile without errors, but when I input a date it first returns the date I have used in my constructor (lines 32-34 of the Date.cpp file), then if I say yes and loop through it again it outputs the date I have set in the Main file (line 11 - DateDriver.cpp). See files below. Really confused - anymore help would be great.
Header file (Date.h)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef Date_H
#define Date_H

#include <iostream>

/*********Class Date Specification**********/

class Date
{
private:
	int month;
	int day;
	int year;	

public:
	Date();
	Date(int m, int d, int y);  // Make sure to give the arguments NAMES
	
	//mutator methods == methods that CHANGE the object
	void setDate(int m, int d, int y);

	//accessor methods == methods that OBSERVE the object
	void getDate(int &m, int &d, int &y) const;  // WHAT ARE the object's current m,d,y values?

	//I/O methods == methods that perform I/O
	void showDate() const;  // this prints to the console, apparenty
	// (You could, conceivably, add a method that reads a date from the console -- something like readDate();.)

	//information and validation functions - these work on ARGUMENTS and do nothing else
	bool isLeap(int y) const;  // is the ARGUMENT y a leap year?
	bool CheckDate(int m, int d, int y) const;  // is the ARGUMENT date m,d,y a valid date?
};
#endif   

Implementation file (Date.cpp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include "Date.h"
using namespace std;

//get user ipmut for the date
void Date::setDate(int month, int day, int year)
{
	cout << "Enter Month: ";
		cin >> month;
		cout << endl;
		cout << "Enter Day: ";
		cin >> day;
		cout << endl;
		cout << "Enter Year: ";
		cin >> year;
		cout << endl;
		
}

//  constructor that initializes all data members
Date::Date(int m, int d, int y)
{
  if(CheckDate(month, day, year))
  {
   month = m;
   day = d;
   year = y;
  }
  else
  {
   cout << "error" << endl;
   month = 1;
   day = 1;
   year = 2000;
  }
}

//get the date 
void Date::getDate(int &m, int &d, int &y) const
{
	m = month;
	d = day;
	y = year;
}



//  print the invoking object in the format mm/dd/yyyy
void Date::showDate() const
{
   cout << month << '/' << day << '/' << year;
}

//test to validate date - calls isLeap
bool Date::CheckDate(int month, int day, int year) const
{
    bool result = true;
    int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(year<1850||year>2100)
		result = false;
	if (isLeap(year))
    {
        daysInMonths[1] = 29;   // Feb has 29 days in leap year
    }
    if (month < 1 || month > 12)
    {
        result = false;
    }
    else if (day < 1 || day > daysInMonths[month-1])
    {
        result = false;
    }
    return result;
}

//test for leap year
bool Date::isLeap(int year) const
    {
    if (year%4==0 && year%100!=0 || year%400==0)
        return true;
    else
        return false;
	}

Main fiel (DateDriver.cpp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
#include "Date.h"

int main()
{
	char choice;
	do
	{
		int month, day, year;
		Date userInput(month =1, day =1, year =2003);

		userInput.getDate(month, day, year);

		
	//display the date
	cout <<"The date you entered is: ";
	userInput.showDate();
	
	cout << "\nWould you like to enter another date?(Y/N)" << endl;
      cin >> choice;
	}
      while(choice != 'n' && choice != 'N');
	
}
Apr 4, 2012 at 3:51pm
Thanks for all the help I finally have this working. One last think I would like to do that is not assigned is to output if an error is returned if an invalid date is entered. Just not sure how to do this.

Header File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef Date_H
#define Date_H

#include <iostream>

/*********Class Date Specification**********/

class Date
{
private:
	int month;
	int day;
	int year;	

public:
	Date();
	Date(int m, int d, int y);  // Make sure to give the arguments NAMES
	
	//mutator methods == methods that CHANGE the object
	void setDate(int m, int d, int y);

	//accessor methods == methods that OBSERVE the object
	void getDate(int &m, int &d, int &y) const;  // WHAT ARE the object's current m,d,y values?

	//I/O methods == methods that perform I/O
	void showDate() const;  // this prints to the console, apparenty
	// (You could, conceivably, add a method that reads a date from the console -- something like readDate();.)

	//information and validation functions - these work on ARGUMENTS and do nothing else
	bool isLeap(int y) const;  // is the ARGUMENT y a leap year?
	bool CheckDate(int m, int d, int y) const;  // is the ARGUMENT date m,d,y a valid date?
};
#endif   

Implementation File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include "Date.h"
using namespace std;

//  constructor that initializes all data members
Date::Date(int m, int d, int y)
{
  if(CheckDate(month, day, year))
  {
   month = m;
   day = d;
   year = y;
  }
}

//get user ipmut for the date
void Date::setDate(int m, int d, int y)
{
	cout << "Enter Month: ";
		cin >> m;
		cout << endl;
		cout << "Enter Day: ";
		cin >> d;
		cout << endl;
		cout << "Enter Year: ";
		cin >> y;
		cout << endl;
	if (CheckDate(m,d,y))
	{
		month = m;
		day = d;
		year = y;
	}	
}


//get the date 
void Date::getDate(int &m, int &d, int &y) const
{
	m = month;
	d = day;
	y = year;
}


//  print the invoking object in the format mm/dd/yyyy
void Date::showDate() const
{
   cout << month << '/' << day << '/' << year;
}

//test to validate date - calls isLeap
bool Date::CheckDate(int month, int day, int year) const
{
    bool result = true;
    int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if(year<1850||year>2100)
		result = false;
	if (isLeap(year))
    {
        daysInMonths[1] = 29;   // Feb has 29 days in leap year
    }
    if (month < 1 || month > 12)
    {
        result = false;
    }
    else if (day < 1 || day > daysInMonths[month-1])
    {
        result = false;
    }
    return result;
}

//test for leap year
bool Date::isLeap(int year) const
    {
    if (year%4==0 && year%100!=0 || year%400==0)
        return true;
    else
        return false;
	}

Main File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <iomanip>
using namespace std;
#include "Date.h"

int main()
{
	int m=1, d=1, y=2004;
	char choice;
	do
	{
		Date userDate(1, 1, 2004);

		userDate.setDate(m, d, y);
		
	//display the date
	cout <<"The date you entered is: ";
	userDate.showDate();
	
	cout << "\nWould you like to enter another date?(Y/N)" << endl;
      cin >> choice;
	}
      while(choice != 'n' && choice != 'N');
	
}
Apr 4, 2012 at 5:14pm
Thanks again for the help. I fixed it with a simple else statement and then used a goto to have the user re-enter their date information.
Apr 5, 2012 at 12:30am
I'm glad you are satisfied, but you still shouldn't be using properties to do I/O.
Apr 5, 2012 at 2:26am

Well I was please that it is working. If I am doing something incorrectly, please give me a little more in site as to what I did wrong. I'd really like to learn to do things properly and not just get the final result. I'm doing this as an online course so access to good information is only between me and my book and a professor that is not always super responsive. As always thanks for any help provided.

Also, my assignment isn't due until next week, so I have some time to get it perfect.
Last edited on Apr 5, 2012 at 2:29am
Apr 8, 2012 at 2:55am
I actually have same assignment. Ive tried to follow all the advice on here but i dont know how to tell the user if an invalid date was entered or to tell if it is a leap year. I'm having a hard time with classes where user inputs information

Header
#ifndef DATE_H
#define DATE_H

#include <iostream>

class Date
{
private:
int month;
int day;
int year;
public:
Date();
Date(int m, int d, int y);
//mutator
void setDate(int m, int d, int y);
//accessor
int getDay() const;
int getMonth() const;
int getYear() const;

void showDate() const;
bool isleap(int y) const;
bool CheckDate(int m, int d, int y) const;
};
#endif


IMPLEMENTATION:

#include "Date.h"
#include <iostream>


using namespace std;

Date::Date()
{
setDate(1, 1, 2000);
}

Date::Date(int m, int d, int y)
{
if (CheckDate(m,d,y))
{
month = m;
day = d;
year = y;
}
}

void Date::setDate(int m, int d, int y)
{
if (CheckDate(m,d,y))
{
month = m;
day = d;
year = y;
}
}
int Date::getYear() const
{
return year;

}
int Date::getDay() const
{
return day;

}
int Date::getMonth() const
{
return month;

}
void Date::showDate() const
{
cout << month << '/' << day << '/' << year;
}

bool Date::CheckDate(int month, int day, int year) const
{
bool result = true;
int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(year<1850||year>2100)
result = false;
if (isleap(year))
{
daysInMonths[1] = 29; // Feb has 29 days in leap year
}
if (month < 1 || month > 12)
{
result = false;
}
else if (day < 1 || day > daysInMonths[month-1])
{
result = false;
}
return result;
}
bool Date::isleap(int year) const
{
if (year%4==0 && year%100!=0 || year%400==0)
return true;
else
return false;
}



MAIN
#include <iostream>
#include <iomanip>
#include "Date.h"

using namespace std;

int main()
{
Date userdate;
char repeat;
int mo, day, yr;

do
{

cout << "Enter the date, ie 5 10 2001: ";
cin >> mo >> day >> yr;
userdate.setDate(mo, day, yr);

cout <<"The date you entered is: ";
userdate.showDate();


cout << "\nWould you like to enter another date?(Y/N)" << endl;
cin >> repeat;
}
while(repeat != 'n' && repeat != 'N');

return 0;
}

also sorry this is my first time posting on here and i dont know how to post the code with line numbers
Last edited on Apr 8, 2012 at 3:02am
Apr 9, 2012 at 3:08am
Sorry to respond so late.

To put code in the fancy boxes with line numbers:

[code]
#include <iostream>
using namespace std;

int main()
{
  cout << "Hello world!\n";
  return 0;
}
[/code]

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main()
{
  cout << "Hello world!\n";
  return 0;
}


I have not looked too closely at your code, but you seem to have a very, very good grasp on it. To check to see if the date is right, just use your Date::CheckDate() member function. In your case, it should not take any arguments; use the internal values instead:

1
2
3
4
bool Date::CheckDate() const
{
  // same stuff as above //
}

Use it to tell the user whether or not he entered a bad date:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <iomanip>
#include "Date.h"

using namespace std;

int main()
{
  Date userdate;
  char repeat;
  int mo, day, yr;

  do
  {

    cout << "Enter the date, ie 5 10 2001: ";
    cin >> mo >> day >> yr;
    userdate.setDate(mo, day, yr);

    cout <<"The date you entered is: ";
    userdate.showDate();

    if (!userdate.CheckDate())
    {
      cout << "(That is an invalid date.)\n";
    }

    cout << "\nWould you like to enter another date?(Y/N)" << endl;
    cin >> repeat;
  }
  while(repeat != 'n' && repeat != 'N');

  return 0;
}

Hope this helps.
Last edited on Apr 9, 2012 at 3:09am
Topic archived. No new replies allowed.