Reputation: 183
I'm currently working on a project for my intro to C++ programming class. The project asks a user to enter a date using mm/dd/yyyy format. Based on the information given, the program then has to determine if the date is valid or invalid, then displays a response to that. I'm facing the problem currently where everything is coming out reading "Good date!" I'm not sure where the problem is. Any help is appreciated. If you could help point me in the right direction, that would be awesome.
#include <iostream>
#include <conio.h>
using namespace std;
void getDate(int *month, int *day, int *year);
int checkDate(int month, int day, int year);
void displayMessage(int status);
int main()
{
int month, day, year;
int s = 0;
getDate(&month, &day, &year);
do
{
checkDate(month, day, year);
displayMessage(s);
getDate(&month, &day, &year);
}
while (_getch() != EOF);
}
void getDate(int *month, int *day, int *year)
{
char fill;
fill = '/';
cout << "Enter a date in mm/dd/yyyy form: ";
cin >> *month;
if (cin.get() != '/')
{
cout << "expected /" << endl;
}
cin >> *day;
if (cin.get() != '/')
{
cout << "expected /" << endl;
}
cin >> *year;
cout << *month << fill << *day << fill << *year << endl;
};
int checkDate(int month, int day, int year)
{
if ((month = 1) || (month = 3) || (month = 5) || (month = 7) ||
(month = 8) || (month = 10) || (month = 12))
{
day <= 31;
}
else if ((month = 4) || (month = 6) || (month = 9) || (month = 11))
{
day <= 30;
}
else if ((month = 2) && (year % 4 == 0))
{
day <= 29;
}
else if ((month = 2) && (year % 4 != 0))
{
day <= 28;
};
int status = 0;
if ((year < 999) || (year > 10000))
{
status == 1;
}
if ((month < 1) || (month > 12))
{
status == 2;
}
else if ((day < 1) || (day > 31))
{
status == 3;
}
else if ((day < 1) || (day > 30))
{
status == 4;
}
else if ((day < 1) || (day > 29))
{
status == 5;
}
else if ((day < 1) || (day > 28))
{
status == 6;
}
return status;
};
void displayMessage(int status)
{
if (status == 0)
{
cout << "Good date!" << endl;
}
if (status == 1)
{
cout << "Bad year" << endl;
}
if (status == 2)
{
cout << "Bad month" << endl;
}
if (status == 3)
{
cout << "Bad day. Not 1-31" << endl;
}
if (status == 4)
{
cout << "Bad day, not 1-30" << endl;
}
if (status == 5)
{
cout << "Bad day, not 1-29" << endl;
}
if (status == 6)
{
cout << "Bad day, not 1-28" << endl;
}
_getch();
}
Upvotes: 3
Views: 30865
Reputation: 218770
Updated answer for C++20:
#include <chrono>
#include <iostream>
void
displayMessage(std::chrono::year_month_day ymd)
{
using namespace std;
using namespace std::chrono;
if (!ymd.year().ok())
{
cout << "Bad year\n";
return;
}
if (!ymd.month().ok())
{
cout << "Bad month\n";
return;
}
if (!ymd.ok())
{
cout << "Bad day, not 1-" << (ymd.year()/ymd.month()/last).day() << '\n';
return;
}
cout << "Good date!\n";
}
int
main()
{
using namespace std::literals;
displayMessage(29d/2/1900);
}
Output:
Bad day, not 1-28
(1900 was not a leap year)
Upvotes: 1
Reputation:
A more compact and stripped checkDate (replace uppercase return by value)
int checkDate(int day, int month, int year) {
if(day < 1 || day > 31) {
return BADVALUE;
} else if(month < 1 || month > 12) {
return BADVALUE;
} else if (year < MINYEAR || year > MAXYEAR) {
return YEAROUTRANGE;
}
if ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) {
return BADMONTHDAY;
} else if ((month == 2) && (year % 4 == 0) && day > 29) {
return BADMONTHYEAR;
} else if ((month == 2) && (year % 4 != 0) && day > 28) {
return BADMONTHYEAR;
}
return GOOD;
}
Upvotes: 0
Reputation: 49
You also could make use of the function mktime()
.
It tries to convert a given tm struct into a correct date. If the comparison of the individual members of the struct subsequently shows equality for all members, the given tm struct contained a valid date.
bool CBorrow::validateDate(tm * timestruct)
{
struct tm copy;
copy.tm_sec = timestruct->tm_sec;
copy.tm_min = timestruct->tm_min;
copy.tm_hour = timestruct->tm_hour;
copy.tm_mday = timestruct->tm_mday;
copy.tm_mon = timestruct->tm_mon;
copy.tm_year = timestruct->tm_year;
copy.tm_wday = timestruct->tm_wday;
copy.tm_yday = timestruct->tm_yday;
copy.tm_isdst = timestruct->tm_isdst;
time_t res = mktime(©);
if (res < 0)
{
return false;
}
if (copy.tm_mday != timestruct->tm_mday
|| copy.tm_mon != timestruct->tm_mon
|| copy.tm_year != timestruct->tm_year)
{
return false;
}
return true;
}
Upvotes: 1
Reputation: 73376
1) There are a couple of issues here, but the most obvious one is in main()
:
int s=0;
...
checkDate(month, day, year); // you don't store the status
displayMessage(s); // so s will always be 0 ! So good date !
You have to correct this:
s=checkDate(month, day, year); // store the result of the check
displayMessage(s); // and take it to display the message
2) Then in checkDate()
, you mixup =
and ==
. =
changes the value of the variable to its left. ==
just makes a comparison but store nothing. When correcting/adjusting, without any optimisation, your code should look like:
int checkDate(int month, int day, int year)
{
int status=0;
if ((month == 1 || month == 3 || month == 5 || month == 7 ||
month == 8 || month == 10 || month == 12) && ( day>31 || day<1) )
{
status = 3;
}
else if ((month == 4 || month == 6 || month == 9 || month == 11) && (day>30 || day<1) )
{
status = 4;
}
else if ((month == 2) && (year % 4 == 0) && (day>29 || day<1))
{
status = 5;
}
else if ((month == 2) && (year % 4 != 0) && (day>28 || day<1) )
{
status = 6;
}
else if ((year < 999) || (year > 10000))
{
status = 1;
}
if ((month < 1) || (month > 12))
{
status = 2;
}
return status;
};
3) After this, you should improve the input function, because:
So keep in mind that (cin>>xxx)
is an expression that you could use in an if
and is true if everything was read correctly. Also be aware that cin.clear()
clears error flags that blocks input after a failure.
Upvotes: 2
Reputation: 1062
Can this also be achieved by a regular expression?
I know there are many drawbacks in this approach, but still may be considered:
#include <regex>
#include <string>
using std::regex;
using std::regex_match;
using std::string;
// for ddmmyy
regex ddmmyy("^([0-2][0-9]|(3)[0-1])(((0)[0-9])|((1)[0-2]))\\d{2}$");
/*
for dd/mm/yy https://regex101.com/r/IqPLBJ/1
for dd/mm/yyyy - could start from \\d{4}$ instead of \\d{2}$ bearing 0000-case in mind
*/
regex slashed_ddmmyy("^([0-2][0-9]|(3)[0-1])\/(((0)[0-9])|((1)[0-2]))\/\\d{2}$");
string f1 = "111223";
bool res = regex_match(f1,ddmmyy); // true
f1 = "112223";
res = regex_match(f1,ddmmyy); // false
res = regex_match(f1, slashed_ddmmyy); // false, no slashes
Upvotes: 0