I'm currently working on writing a date checker function in C and wondering how it can be improved upon.
Q: Write a function that is passed a month, day, and year and will determine if that date is valid. You can assume each parameter is passed in as an integer. Remember to check for leap year.
I currently have this and want to see if there are any beginner mistakes, if pointers could improve efficiency or redundancies in my code.
#include <stdio.h>
#include <stdbool.h>
bool is_valid_date(int month,int day ,int year) {
//Validate year
int days_on_month[]={31,28,31,30,31,30,31,31,30,31,30};
if(year<0||year>2017) {
//year not valid , stop validation , date is invalid
return false;
}
bool isLeapYear;
//Check for leap year , every 4 years there is a leap year
if(year%4==0) {
//if year is evenly divisble by 100 it must also be by 400
if(year%100==0) {
if(year%400==0) {
isLeapYear=true;
}else{
isLeapYear=false;
}
}else{
isLeapYear=true;
}
}
//Validate months;
if(month<1||month>12) {
// not valid , stop validation , date is invalid
return false;
}
//validate day
if(month!=2) {
//Valid Date
if(day>=1&&day<=days_on_month[month-1]){return true;}
}
//February (changes no of days on leap year)
else
{
if(isLeapYear) {
if(day>=1&&day<=29){return true;}
}else{
if(day>=1&&day<=28){return false;}
}
}
return false;
}
// test if function works
int main(void) {
int day = 28;
int month = 12;
int year = 2012;
printf("Is it true? Yes = 1 No = 0! = %d\n", is_valid_date(day, month, year));
return 0;
}
-
\$\begingroup\$ You validate according to the Gregorian calendar. The first full year that calendar was in force for was 1583. No successor to the Gregorian calendar has been announced. So the year validity test should be year>=1583. If you knew the country the date applies to you could refine the validity test to when Gregorian was introduced in that country. \$\endgroup\$Gerard Ashton– Gerard Ashton2017年04月02日 12:42:44 +00:00Commented Apr 2, 2017 at 12:42
2 Answers 2
Some quick formatting tips:
You use whitespace sparingly. In the example code, there is a lot of room for more whitespace that makes the code more readable. Something like:
if (year % 400 == 0) {
isLeapYear = true;
}
It makes the code more easier to read.
Also, and this is not a recommendation but just an option you may want to consider, but you can move the if-else to a new line. I've always found that easier to read, and I've noticed that some (not all) teachers of mine tend to find that good formatting.
So for example:
if(year%400==0) {
isLeapYear=true;
}else{
isLeapYear=false;
}
This code can be rewritten as:
if(year%400==0) {
isLeapYear=true;
}
else{
isLeapYear=false;
}
**As an aside, upon receiving further advice from co-users on CodeReview in the comments, it is better to use curly braces, even if they are solely for one command in an if-statement, as it will help in detecting the scope of the if-statement with more ease.
-
2\$\begingroup\$ Is this a C language thing? I usually hear people say to include curleys always to avoid mistakes. \$\endgroup\$Josh– Josh2017年04月01日 02:44:22 +00:00Commented Apr 1, 2017 at 2:44
-
\$\begingroup\$ @a That's why always using curleys is recommended. I didn't downvote you. \$\endgroup\$Josh– Josh2017年04月02日 10:38:36 +00:00Commented Apr 2, 2017 at 10:38
-
\$\begingroup\$ @Josh I always thought the less the better. Thanks :) \$\endgroup\$BusyProgrammer– BusyProgrammer2017年04月02日 11:19:56 +00:00Commented Apr 2, 2017 at 11:19
You could format things nicely, or at least consistently.
Hardcoding in the current year is a bad idea.
if (year % 400 == 0) {
isLeapYear = true;
} else if (year % 100 == 0) {
isLeapYear = false;
} else if (year % 4 == 0) {
isLeapYear = true;
}
You could put a day < 1 check once, before the other day checks.