Valid_date function

I am having some troubles with the logical operators in "day". What could I do to solve it?
function valid = valid_date(year, month, day)
if ~isinteger(year)
if ~isinteger(month)
if ~isinteger(day)
if ~isscalar(year)
if ~isscalar(month)
if ~isscalar(day)
valid = false;
elseif month == 2
if ((rem(year,4)== 0) && (rem(year,100) ~= 0)) || (rem(year,400)==0)
(1 <= day) && (day <= 28);
valid = true;
else
(1 <= day) && (day <= 29);
valid = true;
end
elseif month == 1 || 3 || 5 || 7 || 8 || 10 || 12
(1 <= day)&(day <= 31);
valid = true;
elseif month == 4 || 6 || 9 || 11
1 <= day <= 30;
valid = true;
else
valid = false;
end
end
end
end
end
end
end

4 Comments

@Denise Gobbo the code really needs to be indented property to make any sense of it.
From the editor, select all of the code [ctrl + a] and apply smart-indent [ctrl+i]
This is how the code should appear so that it's readable. The only thing it's still missing is comments so humans, including your future self, can quickly understand the logic of the code.
function valid = valid_date(year, month, day)
if ~isinteger(year)
if ~isinteger(month)
if ~isinteger(day)
if ~isscalar(year)
if ~isscalar(month)
if ~isscalar(day)
valid = false;
elseif month == 2
if ((rem(year,4)== 0) && (rem(year,100) ~= 0)) || (rem(year,400)==0)
(1 <= day) && (day <= 28);
valid = true;
else
(1 <= day) && (day <= 29);
valid = true;
end
elseif month == 1 || 3 || 5 || 7 || 8 || 10 || 12
(1 <= day)&(day <= 31);
valid = true;
elseif month == 4 || 6 || 9 || 11
1 <= day <= 30;
valid = true;
else
valid = false;
end
end
end
end
end
end
end
This syntax
month == 4 || 6 || 9 || 11
following the rules of operator precedence is equivalent to
(((month == 4) || 6) || 9) || 11
which is equivalent to either of these:
((true || 6) || 9) || 11
((false || 6) || 9) || 11
which because all non-zero values are considered to be true are equivalent to
((true || true) || true) || true
((false || true) || true) || true
which are both equivalent to
(true || true) || true
which is equivalent to
true || true
which is equivalent to
true
which is unlikely to be vey useful. The MATLAB approach is to use ismember:
ismember(month,[4,6,9,11])
Personal preference, perhaps, but I actually like keeping the indenting of the isinteger if statements. To my mind, they are a logical grouping and easier to interpret as that group if they appear at the same level if indentation. Similarly, I usually write
for x = 1:10
for y = 1:10
% do something in x-y space
end
end
because x and y are "on equal footing" as spatial coordinates.
Of course, the point is moot because I'm pretty certain that all those if statements are the not the logic that OP is intending to implement.
Adam Danz
Adam Danz on 18 May 2020
Edited: Adam Danz on 18 May 2020
Thanks for sharing that perspective, @the cyclist . I can see how that grouping can be helpful when the conditional statements are fully nested. If there are additional lines of code outside of the nested structure, I bet it would become difficult to read, though.
eg
for x = 1:10
for y = 1:10
for z = 1:10
% do something in x-y-z space
end
% some code here
end
% some code here
end

Sign in to comment.

Answers (6)

valid = valid_date(2019, 12, 1)
function valid = valid_date(year,month,day)
%check if either year, month, day is not a scalar
if ~isscalar(year) || ~isscalar(month) || ~isscalar(day)
valid =false
return
end
%check if either year, month, day is 0 or negative. check if month is >12
if year<=0 || month>12 || month <=0 ||day<=0
valid =false
return
end
A = [1 3 5 7 8 10 12]; %months with 31 days
B = [4 6 9 11]; %months with 30days
month_31d = sum(ismember(A,month));
%ismember() returns a logical array where element found will be marked as 1 & other positions will be 0
%so only one element in this logical array will be 1 and other elements will be 0 if month falls in this
%month_31d category. Hence sum will be 1 i.e month_31d will be true.
month_30d = sum(ismember(B,month)); %same as above to check whether month falls in the category month_30d
%check for leap year
if rem(year,400)==0
leap_year = true;
elseif rem(year,4)==0 && rem(year,100) ~=0
leap_year =true;
else
leap_year = false;
end
%Check the days for the conditions 28,29,30,31
if month_31d && day>31
valid = false;
elseif month_30d && day>30
valid = false;
elseif (leap_year && month==2 && day>29)||(~leap_year&&month==2&&day>28)
valid = false;
else
valid =true;
end
end

1 Comment

Needs improvement.
try valid_date(nan,nan,nan), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(1234.56,1,7), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(1234,1.23,7), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(1234,1,7.89), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(2021,2,7+3i), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(inf,2,29), catch ME; disp(ME.message); end
ans = logical
0
function valid = valid_date(year,month,day)
%check if either year, month, day is not a scalar
if ~isscalar(year) || ~isscalar(month) || ~isscalar(day)
valid =false
return
end
%check if either year, month, day is 0 or negative. check if month is >12
if year<=0 || month>12 || month <=0 ||day<=0
valid =false
return
end
A = [1 3 5 7 8 10 12]; %months with 31 days
B = [4 6 9 11]; %months with 30days
month_31d = sum(ismember(A,month));
%ismember() returns a logical array where element found will be marked as 1 & other positions will be 0
%so only one element in this logical array will be 1 and other elements will be 0 if month falls in this
%month_31d category. Hence sum will be 1 i.e month_31d will be true.
month_30d = sum(ismember(B,month)); %same as above to check whether month falls in the category month_30d
%check for leap year
if rem(year,400)==0
leap_year = true;
elseif rem(year,4)==0 && rem(year,100) ~=0
leap_year =true;
else
leap_year = false;
end
%Check the days for the conditions 28,29,30,31
if month_31d && day>31
valid = false;
elseif month_30d && day>30
valid = false;
elseif (leap_year && month==2 && day>29)||(~leap_year&&month==2&&day>28)
valid = false;
else
valid =true;
end
end

Sign in to comment.

the cyclist
the cyclist on 18 May 2020
Edited: the cyclist on 18 May 2020
This syntax
1 <= day <= 30
does not check if day is between 1 and 30. You need to do that as two separate checks:
(1 <= day) & (day <= 30);
as you did in the other sections.
Also, for this chain of if statements:
if ~isinteger(year)
if ~isinteger(month)
if ~isinteger(day)
if ~isscalar(year)
if ~isscalar(month)
if ~isscalar(day)
I think you probably actually want a single if statement:
if ~isinteger(year) || ~isinteger(month) || ~isinteger(day) ... and so on
valid = false
end
The way your code is written, if year is an integer, then your function will simply exit, never having evaluated the output variable valid.
Adam Danz
Adam Danz on 18 May 2020
"I am having some troubles with the logical operators in "day"."
That doesn't give us enough background infomation to know what the problem is. Does that mean you're getting an error? The wrong value? The wrong class? An empty output? Is it causing your compute to explode? etc. We can help you more quickly if you tell us what the problem is.
That being said, there are lots of problems with this code and the the problems I immediately see have nothing to do with the 'day' variable.
For example, let's say Year is an interger but Month is not. Read through your code and estimate what would happen. Hint: no output at all.
If you want to return a value of false when the inputs aren't in the correct format,
if ~isinteger(year) || ~isinteger(month) || . . . || ~isscalar(month)
valid = false;
else
% [main part of your code]
end
If you want to determine if the month is 1,3,5,7,8,10 or 12,
if ismember(month, [1 3 5. . .]);
If you want to define values based on differet sets of months,
switch month
case 2
% your code
case {1 3 5 . . .}
% your code
case {4 6 9 . . .}
% your code
otherwise
error('Month did not meet any of the case requrements.')
end
function valid = valid_date (year, month, date)
if ~(isscalar(year) && isscalar(month) && isscalar(date))
valid=false;
elseif year ~= fix(year) || year<1
valid=false;
elseif month ~= fix(month) || month<1 || month>12
valid=false;
elseif date ~= fix(date) || date<1 || date>31
valid=false;
elseif (month == 4 || month == 6 || month == 9 || month == 11) && date>30
valid = false;
elseif month == 2 && ((year/4 ~= fix(year/4) || (year/100 == fix(year/100) && year/400 ~= fix(year/400))) || date>29)&&date>28
valid = false;
else
valid = true;
end

2 Comments

Rik
Rik on 6 Sep 2020
Why did you post a complete solution to a homework question without any explanation? Now your answer is only useful for people wanting to cheat.
Better than some, but could still use improvement.
try valid_date(nan,nan,nan), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(1234.56,1,7), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(1234,1.23,7), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(1234,1,7.89), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(2021,2,7+3i), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(inf,2,29), catch ME; disp(ME.message); end
ans = logical
1
function valid = valid_date (year, month, date)
if ~(isscalar(year) && isscalar(month) && isscalar(date))
valid=false;
elseif year ~= fix(year) || year<1
valid=false;
elseif month ~= fix(month) || month<1 || month>12
valid=false;
elseif date ~= fix(date) || date<1 || date>31
valid=false;
elseif (month == 4 || month == 6 || month == 9 || month == 11) && date>30
valid = false;
elseif month == 2 && ((year/4 ~= fix(year/4) || (year/100 == fix(year/100) && year/400 ~= fix(year/400))) || date>29)&&date>28
valid = false;
else
valid = true;
end
end

Sign in to comment.

Ahmed Saleh
Ahmed Saleh on 21 Mar 2021
Edited: Ahmed Saleh on 21 Mar 2021
function valid = valid_date(year,month,day)
y= year;
m=month;
d=day;
days_1=[31 28 31 30 31 30 31 31 30 31 30 31];
if (fix(y/4)==(y/4) && fix(y/100)~=(y/100)) || (fix(y/4)==(y/4) && fix(y/100)==(y/100) && fix(y/400)==(y/400))
days_1(2)=29;
end
if ~isscalar(y) || ~isscalar(m) || ~isscalar(d)
valid= false;
return
elseif y<=0 || m<=0 || d<=0 || m>12 || d>31
valid = false;
return
elseif days_1(m)<d
valid=false;
return
else
valid=true;
end

4 Comments

Rik
Rik on 21 Mar 2021
No formatting, no explanation. How is this going to teach anyone anything? Why should it not be deleted?
Let's see...
try valid_date(nan,nan,nan), catch ME; disp(ME.message); end
Array indices must be positive integers or logical values.
try valid_date(1234.56,1,7), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(1234,1.23,7), catch ME; disp(ME.message); end
Array indices must be positive integers or logical values.
try valid_date(1234,1,7.89), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(2021,2,7+3i), catch ME; disp(ME.message); end
ans = logical
1
try valid_date(inf,2,29), catch ME; disp(ME.message); end
ans = logical
1
function valid = valid_date(year,month,day)
y= year;
m=month;
d=day;
days_1=[31 28 31 30 31 30 31 31 30 31 30 31];
if (fix(y/4)==(y/4) && fix(y/100)~=(y/100)) || (fix(y/4)==(y/4) && fix(y/100)==(y/100) && fix(y/400)==(y/400))
days_1(2)=29;
end
if ~isscalar(y) || ~isscalar(m) || ~isscalar(d)
valid= false;
return
elseif y<=0 || m<=0 || d<=0 || m>12 || d>31
valid = false;
return
elseif days_1(m)<d
valid=false;
return
else
valid=true;
end
end
Rik, please leave this one, as my unit tests are instructive.
Rik
Rik on 21 Mar 2021
@Walter Roberson I agree, and have consequently remove the flag.

Sign in to comment.

% this is my answer
function valid = valid_date(year, month, day);
if day<=0 || month <=0 || ~isscalar(year) ||~isscalar(month)||~isscalar(day)||mod(day,1)~=0 ||mod(month,1)~=0||mod(year,1)~=0;
valid = false;
elseif month>12;
valid = false;
elseif (month==1 || month==3|| month==5||month==7||month==8||month==10||month==12)&& day>31;
valid = false;
elseif (month==4||month==6||month==9||month==11)&&day>30;
valid = false;
elseif (month == 2 && ((mod(year,4)==0 && mod(year,100)~=0)||(mod(year,400)==0)) ) && day>29
valid =false;
elseif month== 2 && ~((mod(year,4)==0 && mod(year,100)~=0)||(mod(year,400)==0)) && day>28;
valid= false;
else;
valid =true;
end;

1 Comment

I added an extra end to your function, but after that it passes almost all the unit tests by Walter (you only missed the complex-valued input) and you missed my addition (different datatype).
So now only the question remains why you decided to post this solution to a homework question?
try valid_date(nan,nan,nan), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(1234.56,1,7), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(1234,1.23,7), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(1234,1,7.89), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(2021,2,7+3i), catch ME; disp(ME.message); end
Arguments must be real.
try valid_date(inf,2,29), catch ME; disp(ME.message); end
ans = logical
0
try valid_date(struct,2,28), catch ME; disp(ME.message); end
Undefined function 'mod' for input arguments of type 'struct'.
function valid = valid_date(year, month, day);
if day<=0 || month <=0 || ~isscalar(year) ||~isscalar(month)||~isscalar(day)||mod(day,1)~=0 ||mod(month,1)~=0||mod(year,1)~=0;
valid = false;
elseif month>12
valid = false;
elseif (month==1 || month==3|| month==5||month==7||month==8||month==10||month==12)&& day>31
valid = false;
elseif (month==4||month==6||month==9||month==11)&&day>30
valid = false;
elseif (month == 2 && ((mod(year,4)==0 && mod(year,100)~=0)||(mod(year,400)==0)) ) && day>29
valid =false;
elseif month== 2 && ~((mod(year,4)==0 && mod(year,100)~=0)||(mod(year,400)==0)) && day>28
valid= false;
else
valid =true;
end
end

Sign in to comment.

Categories

Asked:

on 18 May 2020

Commented:

Rik
on 22 Sep 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!