Date checker is not working - false negative - java

So I got an assignment to build a Date class. When I am receiving a day, month and a year as parameters, I need to make sure that the Date is valid. I do it by calling a function named isDateValid. According to the instructions, if the date is valid, the parameters will be set has the properties of the class, otherwise, I need to create the date with the default value of 1/1/2000. however, when I run the testers the university has provided, it seems that even if the Date is valid, the actual Date will be set the default - meaning that the function isDateValid is returning false when it is supposed to return true.
Here is one of the objects created by the tester:
Date d1 = new Date(3, 5, 1998);
, when I run it, I get the default date.
the function is:
private boolean isDateValid(int day, int month, int year)
{
return (((month == JANUARY || month == MARCH || month == JULY || month == AUGUST || month == OCTOBER || month == DECEMBER || month == MAY) &&
day <= DAYS_IN_JAN_MAR_MAY_JUL_AUG_OCT_DEC) ||
((month == APRIL || month == JUNE || month == SEPTEMBER || month == NOVEMBER) && day <= DAYS_IN_JUN_APR_SEP_NOV) ||
(((month == FEBRUARY && day <= DAYS_IN_FEB_LEAP)) || (isLeapYear(year) && day <= DAYS_IN_FEB_NO_LEAP && month == FEBRUARY)) ) &&
( day >= MINIMUM_DAY && month >= MINIMUM_MONTH && month <= MAXIMUM_MONTH && year >= MINIMUM_YEAR && year <= MAXIMUM_YEAR);
}
Here are the contants being used:
private final int MINIMUM_YEAR = 1000;
private final int MINIMUM_MONTH = 1;
private final int MINIMUM_DAY = 1;
private final int MAXIMUM_DAY = 31;
private final int MAXIMUM_MONTH = 12;
private final int MAXIMUM_YEAR = 9999;
private final int JANUARY = 1;
private final int FEBRUARY = 2;
private final int MARCH = 3;
private final int APRIL = 4;
private final int MAY = 5;
private final int JUNE = 6;
private final int JULY = 7;
private final int AUGUST = 8;
private final int SEPTEMBER = 9;
private final int OCTOBER = 10;
private final int NOVEMBER = 11;
private final int DECEMBER = 12;
private final int DAYS_IN_JAN_MAR_MAY_JUL_AUG_OCT_DEC = 31;
private final int DAYS_IN_JUN_APR_SEP_NOV = 30;
private final int DAYS_IN_FEB_NO_LEAP = 28;
private final int DAYS_IN_FEB_LEAP = 29;
Edit:
I got a comment suggesting that the source of the error can be somewhere else, so I will provide all related code to this function:
this is the function I use in order to determent whether or not it is a leap year
private static boolean isLeapYear(int year) {
if (year % 4 != 0) {
return false;
} else if (year % 400 == 0) {
return true;
} else if (year % 100 == 0) {
return false;
} else {
return true;
}
}
and here is the constructor of the Date class:
public Date (int day, int month, int year)
{
if(isDateValid(day, month, year))
{
_day = day;
_month = month;
_year= year;
}
else
{
_day = DEFULTE_DAY;
_month = DEFULTE_MONTH;
_year = DEFULTE_YEAR;
}
}
I really can't determent what is the problem, and the fact that it is one complex condition and not multiple if statements make it hard to debug.
Since it is an assignment I am not allowed to use "actual java" - the java date class etc...
Where did I was mistaken?
Thank you in advance!

As you've sort of identified, that return statement is hard to debug. I'd break it up into manageable sections.
private boolean isDateValid(int day, int month, int year) {
bool retVal = true;
retVal = retVal && (month >= JANUARY) && (month <= DECEMBER);
retVal = retVal && (day >= 1) && (day <= DAYS_IN_JAN_MAR_MAY_JUL_AUG_OCT_DEC);
if (month == APRIL || month == JUNE ...) {
retVal = retVal && (day < DAYS_IN_JUN_APR_SEP_NOV);
}
if (month == FEBRUARY) {
.. handle the complex case of February
}
return retVal;
}
Note also that because January through December are values in the range [1..12] without gaps, you don't need to check month against each value but can just check within January..December. That makes this a little simpler.
That weird-ass complicated return statement is just begging for something problematic. It's too easy to get something that complicated wrong.

I have tested your isDateValid method with every valid date from year 1799 through 2100 and with every valid date in year 1000 and year 9999. It returns true every time. Also for the example date you gave, isDateValid(3, 5, 1998) returns true. So I believe that the cause for returning a default date doesn’t lie within the isDateValid method that you have posted. I can’t tell you where then, but you need to look elsewhere.
You have got a bug, though: isDateValid(29, 2, 1999) returns true. 1999 was not a leap year, so it should return false. So let’s examine the code dealing with February:
((month == FEBRUARY && day <= DAYS_IN_FEB_LEAP))
|| (isLeapYear(year) && day <= DAYS_IN_FEB_NO_LEAP && month == FEBRUARY)
(I have broken it over two lines to fit it better into Stack Overflow.) In case of 29th February in a leap year, the first line evaluates to true. Since there is || (logical or) between the two lines, true is the result of the entire expression. Java uses lazy evaluation here and doesn’t even evaluate the second line, but even if it did, the result of the logical or operation would still be true.
You could probably find a way to fix it, but you shouldn’t. Instead rewrite your entire method along the lines in the other answer.

Related

java difference between two dates using only logic, no calender, date or similar

this is what I've got so far, but all I get is zero for the output. I've tried for loops that are separate for the first year and last year to calculate just the months in those years then a separate for loop for the years inbetween since they would be full years and still I get the wrong output. I just need some guidance and as the title says I can't use calender or date or any other similar class just loops and logic.
package cop2250.spring18.week3.ledesma;
import java.util.Scanner;
public class Week3assignment1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int days1 = 0, days2 = 0, days3 = 0, totalDays = 0, month3 = 0, betweenYears, year3;
System.out.println("Enter a starting Date in the format mm-dd-yyyy: ");
String[] startDate = input.next().split("-");
int month1 = Integer.parseInt(startDate[0]);
int day1 = Integer.parseInt(startDate[1]);
int year1 = Integer.parseInt(startDate[2]);
System.out.println("Enter an ending Date in the format mm-dd-yyyy: ");
String[] endDate = input.next().split("-");
int month2 = Integer.parseInt(endDate[0]);
int day2 = Integer.parseInt(endDate[1]);
int year2 = Integer.parseInt(endDate[2]);
for(year3 = 0; year3 > year1 && year3 < year2; year3++) {
for (month3 = 0; month3 < 12; month3++) {
days1 = daysInMonth(year3, month3);
}
totalDays =+ days1;
}
System.out.println("Days is : "+ totalDays);
}
private static boolean isLeapYear(int year) {
return year % 400 == 0 || (year % 4 == 0 || year % 100 == 0);
}
private static int daysInMonth(int year, int month) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return 31;
if (month == 4 || month == 6 || month == 9 || month == 11)
return 30;
if (month == 2)
return isLeapYear(year) ? 29 : 28;
return 0;
}
}
I see some issues here:
The outer loop starts from 0, shouldn't it start from year1?
The inner loop numbers months from 0 to 11 but the method you call numbers them from 1 to 12.
x =+ y is quite different from x += y.
If I give a date in 2016 and one in 2017 it looks to me like you are counting the days of all the months in those two years. So the inner loop also need to consider the given months (and days):

Project Euler #19 - 2 less

I would like to ask someone if he/she can help me find the bug where I lose 2 solutions in this problem. My code isn't very pretty and readable but I think it is simple enough to understand logic here. I am sitting on this one for hour and even made up different solution which works but can't find problem in this one.
private static int _year = 1900;
private static int[] _months = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
private static int _month = 0;
private static int _day = 7; //we start from Sunday
private static int counter = 0;
public static void main(String[] args) {
while(_year !=1901)
nextSunday(_day, _month, _year);
while(true) {
if(_year == 2000 && _month == 11 && _day > 31) break;
nextSunday(_day, _month, _year);
}
System.out.println(counter);
}
private static void nextSunday(int day, int month, int year) {
if(isSundayFirst(_day)) counter++;
if(year == 2000 && month == 11 && day + 7 > _months[month]) { //to break loop
_day = day + 7;
} else if(month == 11 && day + 7 > _months[month]) { // new year, end of month
_day = day + 7 - _months[month];
_month = 0;
_year++;
} else if(month == 1 && isLeapYear(year) && day + 7 > 29) { // leap year end of february
_day = day + 7 - 29;
_month++;
} else if(month == 1 && !isLeapYear(year) && day + 7 > _months[month]) { // not leap year end of february
_day = day + 7 - _months[month];
_month++;
} else if(day + 7 > _months[month]) { // end of month
_day = day + 7 - _months[month];
_month++;
} else { // next in same month
_day = day + 7;
}
}
private static boolean isSundayFirst(int day) {
return day == 1;
}
private static boolean isLeapYear(int year) {
if(isCentury(year)) {
if(year % 400 == 0) return true;
} else {
return year % 4 == 0;
}
return false;
}
private static boolean isCentury(int year) {
return year % 100 == 0;
}
I got 169 such Sundays. I should get 2 more.
Here is the problem:
You are given the following information, but you may prefer to do some
research for yourself.
1 Jan 1900 was a Monday.
Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth
century (1 Jan 1901 to 31 Dec 2000)?
I will appreciate any effort. Thank you.
PS I know this _name style isn't Java like but I was writing it fast without intention of posting it anywhere tbh.
There are two issues with your code, one that causes you to over count by 2 and another that causes you to undercount by 4.
Issue #1 The problem to tells you to start counting in 1901, but you start counting in 1900.
Change
if(isSundayFirst(_day)) counter++;
to
if(isSundayFirst(_day) && _year >= 1901) counter++;
to fix this.
Issue #2 The issue lies in this condition:
else if(day + 7 > _months[month]) { // end of month
_day = day + 7 - _months[month];
_month++;
}
You've handled the case where it is February in the previous two conditions, so you need to check to make sure it is not February here. Changing the condition to
else if(month != 1 && day + 7 > _months[month])
will fix your issue.
Sidenote: The structure of your nextSunday method made it quite difficult to decipher, so here is my effort to simplify it (you will now break when _year > 2000):
private static void nextSunday(int day, int month, int year) {
int febNum = isLeapYear(_year) ? 29 : 28;
int dayCount = (month == 1) ? febNum : _months[_month]; //days in current month
_day += 7;
if (_day > dayCount) { //new month
_month++;
_day -= dayCount;
}
if (_month == 12) { //new year
_month = 0;
_year++;
}
}

Why does my code step into an else-if statement whose condition should be false?

I have a method that is supposed to return the seasons of the year depending upon the month and day. The first three times I call the method it works fine. However, the fourth method returns spring when it should return fall.
It should bypass the else-if statement for spring and continue down to fall but when I debug it, that is not what it does. it goes into that else-if and returns it.
I tried moving the months and dates around but no matter where I put it, it returns spring. I cannot figure out why since the arguments do not meet the criteria for that particular statement.
Here is my code:
public static void main(String[] args) {
System.out.println(season(1, 5));
System.out.println(season(4, 12));
System.out.println(season(7, 1));
System.out.println(season(10, 31));
}
public static String season(int month, int day) {
if(month >= 12 && day >= 16 || month <= 3 && day <= 15) {
return "winter";
} else if(month >= 3 && day >= 16 || month <= 6 && day <= 15) {
return "spring";
} else if(month >= 6 && day >= 16 || month <= 9 && day <= 15) {
return "summer";
} else {
return "fall";
}
}
Your program is doing exactly what you told it to. When you call season(10, 31), you get to the test:
if (month >= 3 && day >= 16 || ...)
which is true because the month is 10 and the day is 31 (both greater than their targets in this test). Clearly, this is not what you want. So you have to make a slightly more complicated test:
if (month == 3 && day >= 16 || month > 3 && month < 6 || month == 6 && day <= 15)
This tests the day only if the month is not the starting or ending month for spring. Your other tests will need similar adjustments.
You may find that you might like to add parentheses to your tests to help group them as suggested by other answers here, but due to the Java operator precedence, it is not strictly necessary in this case.
If you remove first half of your conditions it will work fine.
public static String season(int month, int day)
{
if(month <= 3 && day <= 15)
{
return "winter";
}
else if(month <= 6 && day <= 15)
{
return "spring";
}
else if(month <= 9 && day <= 15)
{
return "summer";
}
else
{
return "fall";
}
}

Iterate over subrange of weekdays

I'm trying to iterate over a range of weekdays, where each weekday maps to an integer (Sunday = 1, Monday = 2, ..., Saturday = 7).
The range is defined by a start and end day. This is fine for a start and end day like Monday(2) - Thursday(5), as I can just do:
for(int i = startDay; i <= endDay; i++) { ... }
I'm having difficulty when the range is split across the end and start of a week, like Friday(6) - Monday(2). This obviously doesn't work with the above for loop - e.g.
for(int i = 6; i <= 2; i++) { ... } // wouldn't even execute once.
The only solution I can see is implementing some sort of circular buffer, which I feel is overkill for such a simple problem. I'm just stumped, and most likely missing something obvious here. I think a solution may have something to do with modular arithmetic, but I'm not quite sure.
You can do:
int numberOfDays = endDay >= startDay ? endDay - startDay : 8 - (startDay - endDay);
for (int i = startDay; i <= startDay + numberOfDays; i++) {
int day = (i - 1) % 7 + 1;
}
This makes use of the % modulo operator to ensure all values remain within 1 - 7.
For example, once i becomes 8 the calculation will wrap day back to 1: (8 - 1) % 7 + 1 == 1.
It's probably clearest just to use a break, then you don't have to worry about all the different cases:
for (int day = startDay; ; day = (day - 1) % 7 + 1) {
// ... do your stuff
if (day == endDay) {
break;
}
}
or, some might prefer this:
int day = startDay;
while (true) {
// ... do something
if (day == endDay) {
break;
}
day = (day - 1) % 7 + 1;
}
or:
int day = startDay;
while (true) {
// ... do something
if (day == endDay) {
break;
}
if (++day > 7) {
day = 1;
}
}
Trying to get all the different cases right with a for loop can be a headache. You have to make sure these are handled:
startDay == 1, endDay == 7
endDay == startDay
endDay == startDay - 1 (which should go through every day of the week in some order)
endDay > startDay
endDay < startDay
In Java 8:
// input section
DayOfWeek start = DayOfWeek.FRIDAY;
DayOfWeek end = DayOfWeek.MONDAY;
// execution section
DayOfWeek dow = start;
DayOfWeek stop = end.plus(1);
do {
// ... your code
dow = dow.plus(1);
} while (dow != stop);
The do-while-construction ensures that for the condition start == end the loop will be executed at least once.
UPDATE due to use of your localized indices (Sunday = 1 instead of 7)
You can convert the indices to DayOfWeek-objects this way:
private static DayOfWeek convert(int localIndex) {
int iso = localIndex - 1;
if (iso == 0) {
iso = 7;
}
return DayOfWeek.of(iso);
}
You can use a % operator for some sort of circularity
for (int i=6; i!=2; i=(i+1)%7) { ... }
That will index days from 0, so Sunday = 0 ... Saturday = 6. If you really want to have index starting from 1 it's only interpretation problem. You can for example do:
for (int i=6; i!=2; i=(i+1)%7) {
int day=i+1;
// use day here
}

This method must return a result of type int

I attempt to create a function in Java that checks the days in months from 1582 to 2199. Event if i have return statements of int type i get the following error : This method must return a result of type int
See my sample of code:
/------------------------- daysInMonth ----------------------/
public static int daysInMonth(int year, int month)
{
//returns the number of days in month of year, or -1 if date is invalid.
//October 1582 has 16 days (16th-31st)
if (year < 1582 || year > 2199)
return -1;
else if(month == 1 || month ==3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return 31;
}
There is a combination of parameters when no return is called in your method. Javac is smart enough to notice that and it won't compile such code as it can lead to unexpected behavior
Event if i have return statements of int type i get the following error : This method must return a result of type int
Yes you do return int, though if the statements all are false. If we do something like daysInMonth(1000, 100); then the program is confused because it ends up at a point where there is nothing to return.
Simply add a else after the else if or just add a return in the end of the method.
public static int daysInMonth(int year, int month)
{
//returns the number of days in month of year, or -1 if date is invalid.
//October 1582 has 16 days (16th-31st)
if (year < 1582 || year > 2199)
return -1;
else if(month == 1 || month ==3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return 31;
return -1;
}
You should also write a case if none of the two conditions meet. So better write a case for else after else if.
And what should happen if none of the conditions are satisfied?
I would suggest something like this
int ret = 0;
if (year < 1582 || year > 2199)
ret = -1;
else if(month == 1 || month ==3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
ret = 31;
return ret;
You forgot to end your if-else statement with an else case.
You should add these lines
else if(month==2)
{
if( year%4==0 )
return 29;
else
return 28;
}
else if( month==4|| month==6|| month==9|| month==11)
return 30;
return -1;

Categories