public static void main(String[] args){
boolean year = isLeapYear(9999);
System.out.println("Is Leap Year: " + year);
}
public static boolean isLeapYear(int year){
int rem4 = year % 4;
int rem100 = year % 100;
int rem400 = year % 400;
if ((year >= 1 && year <= 9999) && (rem4 == 0) && (rem100 == 0 && rem400 == 0) || (rem100 != 0) && (rem4 == 0)){
return true;
}
return false;
}
When I enter a negative year (so far only -1024) my range condition doesn't work.
But if I enter any other negative leap year it works(-2020). So I don't know what I'm possibly missing, or if the structure of the algorithm is quite right. Any help will be appreciated.
What is expected is that when I enter a year that is not a leap year, and if it is a negative leap year, it returns false.
I know it's considered cool to be concise and all, but this kind of thing is often best done with multiple simple conditionals. Especially when you're first developing it.
if (year < 1 || year > 9999)
return false;
if (rem4 != 0)
return false;
if (rem100 == 0 && rem400 != 0)
return false;
return true;
Or, perhaps:
if (year >= 1 && year <= 9999)
if (rem4 == 0) {
if (rem100 == 0)
return (rem400 == 0);
return true;
}
return false;
Either way will be easier to debug than one big long complicated if statement.
Not exactly sure, but maybe it's because when
|| (rem100 != 0) && (rem4 == 0)) returns a true statement, your whole function returns true, negating the whole first part of your if-statement.
As the || overrides the positive validation part, just add that same validation in the other part of the condition...
(year >= 1 && year <= 9999 && rem4 == 0 && rem100 == 0 && rem400 == 0 || year >= 1 && year <= 9999 && rem100 != 0 && rem4 == 0)
Related
I am trying to write a program which shows the number of days in a given month of a year. The outputs for the month of February, non leap years (no output) and the months having 30 days in leap years is incorrect (output is 29). How could I resolve this?
public class Q11 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner number1 = new Scanner(System.in);
Scanner number2 = new Scanner(System.in);
System.out.println("Enter the month (1-12)");
int month = number1.nextInt();
System.out.println("Enter the year");
int year = number2.nextInt();
int number_of_days = 0;
boolean N1 = (month == 1) ||
(month == 3) ||
(month == 5) ||
(month == 7) ||
(month == 8) ||
(month == 10) ||
(month == 12);
boolean N2 = (month == 2) && (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);
boolean N3 = (month == 2) && (year % 400 <= 1) || (year % 4 <= 1) && (year % 100 == 0);
boolean N4 = (month == 4) ||
(month == 6) ||
(month == 9) ||
(month == 11);
if (N1)
System.out.println(". This month has 31 days");
else if (N2)
System.out.println(". This month has 29 days");
else if (N3)
System.out.println(". This month has 28 days");
else if (N4)
System.out.println(". This month has 30 days");
}
}
Problem
You run into a problem due to the fact how the program evaluates your boolean expressions. Remember the rules for boolean precedence. && is evaluated first and takes precedence. Also, the formula is evaluated from left to right. Operator precedence can be overruled with the correct setting of parentheses.
E.g. if you have a && b || c, a && b is evaluated first, after which we evaluate its result against || c. But: a && (b || c) is evaluated by first evaluating b || c and then evaluating this result against && a.
In your case, when you enter e.g. month = 4 and year = 2020 the following happens:
The rule n1 is skipped - month is not listed.
The rule n2 is evaluated - month is not equals to two and the year is not divisible by 400; so far everything goes to plan. But now - the next || comes around to bite you. The year is divisible by 4 AND it is not divisible by 100. The program now incorrectly prints 29.
The rules n3 and n4 are solved like n2 and are left as an exercise for the reader :)
Solution
Easiest way is to understand why n2 is failing and optimize the formula. Since this is a homework task I don't want to solve it for you.
General
One scanner instance on System.in is enough.
Your variable names should follow the Java naming convention, lowerCaseCamelCase instead of snake_case and N1.
Parting thought
Try using a switch statement on month - it will make your code a bit easier to understand. Finally: Good luck in your studies.
In your existing code make the following changes.
this checks for leap year.
if it is divisible by 4 and not a century year, its is a leap year
or if is divisible by 400 it is a leap year.
otherwise, it isn't.
boolean N2 = (year %4 == 0 && year %100 != 0) || (year % 400 == 0);
Now just use the negation of the boolean to test for non leap year.
if (N1)
System.out.println(". This month has 31 days");
else if (N4) {
System.out.println(". This month has 30 days");
} else if (month == 2) {
boolean N2 = (year %4 == 0 && year %100 != 0) || (year % 400 == 0);
if (N2) {
System.out.println("This month has 29 days");
} else {// must not be leap year.
System.out.println("This month has 28 days");
}
} else {
System.out.printf("Bad month(%d) entered", month);
}
Also, you should only use one Scanner for all console input.
An alternative approach
In case you didn't know, the enhanced switch statement introduced in Java 13 would be perfect for this.
it takes multiple cases
and returns an argument for processing.
public class Q11 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the month (1-12)");
int month = scanner.nextInt();
System.out.println("Enter the year");
int year = scanner.nextInt();
boolean isLeapYear = (year %4 == 0 && year %100 != 0) || (year % 400 == 0);
String proclamation = switch(month) {
case 1,3,5,7,8,10,12 -> "This month has 31 days.";
case 4,6,9,11 -> "This month has 30 days";
case 2 -> "This month has %d days".formatted(isLeapYear ? 29 : 28);
default -> "Bad month (%d) entered.".formatted(month);
};
System.out.println(proclamation);
}
}
I am getting different results: -1 if I use parentheses and 1 if I don't use parentheses.
For test case "30/10/2019" I am getting -1 if I use parentheses and 1 if I don't use parentheses in the following line:
else if((mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) && mm<13 && mm>0 && dd>0 && dd<32) return 1;
What is the difference between above line and below line?
else if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12 && mm<13 && mm>0 && dd>0 && dd<32) return 1;
public class Utility {
public static int checkDate(String date){
String []st;
if((date.charAt(2)=='.' && date.charAt(5)=='.')||(date.charAt(2)=='/' && date.charAt(5)=='/')||(date.charAt(2)=='-' && date.charAt(5)=='-'))
{
String token = Character.toString(date.charAt(2));
if(date.charAt(2) == '.') st = date.split("\\.");
else st = date.split(token);
int dd = Integer.parseInt(st[0]);
int mm = Integer.parseInt(st[1]);
int yy = Integer.parseInt(st[2]);
if(mm == 2 && dd>0 && dd<30 && mm<13 && mm>0) return 1;
else if((mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) && mm<13 && mm>0 && dd>0 && dd<32) return 1;
else if((mm==4||mm==6||mm==9||mm==11) && dd>0 && dd<31 && mm<13 && mm>0) return 1;
else return -1;
}
else return -1;
}
}
import java.util.Scanner;
public class DateValidation {
public static void main(String[] args) {
// STUDENT CODE BEGINS HERE
Scanner sc = new Scanner(System.in);
String dt=sc.next();
Utility ut = new Utility();
int flag = ut.checkDate(dt);
if(flag==1)
System.out.println("Valid");
else
System.out.println("Invalid");
// STUDENT CODE ENDs HERE
}
}
It will execute the following (in highest order of precedence):
Parentheses ()
Not !
And &&
Or ||
else if((mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) && mm<13 && mm>0 && dd>0 && dd<32)
return 1;
It will evaluate (mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12) first, then && mm<13 && mm>0 && dd>0 && dd<32
else if(mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12 && mm<13 && mm>0 && dd>0 && dd<32)
return 1;
As for the other, it will evaluate mm<13 && mm>0 && dd>0 && dd<32 first, then mm==1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12 &&
Parentheses decide the order these booleans are resolved. And binds stronger than Or. In your case you ask for:
mm==12 && mm<13
So left comparison and right comparison must resolve to true. They don't, as you are in month 10. With parenthesis you decide to check if your month value is valid at all, this resolves to true, and then the && check resolves to true as well.
Consider this example.
int a = 5;
System.out.println((a == 5 || a == 10) && a == 8 || a == 9); // false
// evaluates to true && false || false which is false
System.out.println(a == 5 || a == 10 && a == 8 || a == 9); // true
// evaluate to true || false && false && false
// the first true, wins because it is followed by an || so the whole
// expression evaluates to true.
With a && b both both a and b must be true for the statement to be true
With a || b only one of a and b must be true.
This also goes for grouped expressions.
If one expression is true and the other is false, the complete expression is false for && and true for ||. These operators work from left to right so you need to group appropriately, just like arithmetic expressions.
The best advice is always use parentheses to ensure proper evaluation of expressions.
Assumptions: 1 of 3 of the conditions will be 0.
If I have an if statement defined as follows:
if ((condition1 == 0) || condition2 == 0) || condition3 == 0)) {
do something
}
and 3 following else if statements:
else if (condition1 != 0) {
do something
print which of condition 2 or 3 was 0
}
else if (condition2 != 0) {
do something
print which of condition 1 or 3 was 0
}
else if (condition3 != 0) {
do something
print which of condition 1 or 2 was 0
}
I was thinking perhaps putting nested if statements in the first if statement to see which of the three was 0.
Came up with something. What terrible practice it is to be using this many if statements though. (assume memorizeCondition is stored outside the method of ifs)
if (condition1=0 || condition2 = 0 || condition3 = 0)
if(condition1 = 0)
memorizeCondition = condition1;
if(condition2 = 0)
memorizeCondition = condition2;
if(condition3 = 0)
memorizeCondition = condition3;
else if (condition1 != 0)
memorizeCondition;
calculate condition1;
calculate other condition;
else if (condition2 != 0)
memorizeCondition;
calculate condition2;
calculate other condition;
else if (condition3 != 0)
memorizeCondition;
calculate condition2;
calculate other condition;
what about this:
if ((condition1 == 0) || condition2 == 0) || condition3 == 0)) {
do something
} else {
if (condition1 != 0) {
do something
print which of condition 2 or 3 was 0
}
if (condition2 != 0) {
do something
print which of condition 1 or 3 was 0
}
if (condition3 != 0) {
do something
print which of condition 1 or 2 was 0
}
}
If there are a lot more than 3 conditions you can add them to a collection and then use stream.filter() to remove all non matching conditions.
This is my updated code, it still doesn't work. It returns day for all cases of Feb. 29th, when it should only return day if it is a leap year, if it is not a leap year 1 should be returned.
public int checkDay (int day)
{
// For months with 30 days.
if ((month == 4 || month == 6 || month == 9 || month == 11) && day <= 30)
return day;
// For months with 31 days.
if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day <= 31))
return day;
// For leap years.
// If February 29th...
if (month == 2 && day == 29)
{
// Check if year is a leap year.
if ((year%4 == 0 && year%100!=0) || year%400 == 0)
{
// If year is a leap year return day as 29th.
return day;
}
// If not a leap year, return day as 1st.
else return 1;
}
// If Date if February 1st through 28th return day, as it is valid.
if (month == 2 && (day >= 1 && day <= 28))
return day;
// Return day as 1st for all other cases.
return 1;
}
Try GregorianCalendar http://docs.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html
GregorianCalendar gc = new GregorianCalendar();
if (gc.isLeapYear(year) )
Try changing your code as
if (year%4==0&&(year%100!=0&&year%400==0))
if ((year%4==0 && year%100!=0) || year%400==0)
this solves your problem, your logic was false :)
try this code: if the returned boolean is false you can set the day to 1, because the date is not valid.
public bool checkDay (int day, int month, int year){
bool valid = false;
if(day >=1){
// For months with 30 days.
if ((month == 4 || month == 6 || month == 9 || month == 11) && day <= 30){
valid = true;
}
// For months with 31 days.
if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && day <= 31){
valid = true;
}
// For February.
if (month == 2)
{
if(day <= 28){
valid = true;
} else if(day == 29){
if ((year%4 == 0 && year%100!=0) || year%400 == 0){
valid = true;
} //else invalid
}
}
} //else date is not valid
return valid;
}
It is better practice to have only one return statement in each method. That makes it easier to understand the code and by that to debug it and find possible errors. If you have any problems, feel free to ask.
I have a homework assignment which asks to have the user input a date in Java in the (mm/dd/yyyy) format, then to determine if the entered date is valid. I have been able to successfully do this for every month, save February, because you must take leap years into account.
I have this code:
import java.util.Scanner;
/**
*
* #author Andrew De Forest
* #version v1.0
*
*/
public class exc6
{
public static void main (String[] args)
{
//Initialize a string
String getInput;
//Initialize some integers
int month, day, year;
//Make a boolean
boolean validDate;
//Set the date to false
validDate = false;
//Ask for input
System.out.println("Enter a date (mm/dd/yyyy)");
//Initialize the scanner
Scanner keyboard = new Scanner (System.in);
//Get input & use a delimiter
keyboard.useDelimiter("[/\n]");
month = keyboard.nextInt();
day = keyboard.nextInt();
year = keyboard.nextInt();
if((month >= 1 && month <= 12) && (day >= 1 && day <= 31))
{
//For months with 30 days
if((month == 4 || month == 6 || month == 9 || month == 11) && (day <= 30))
{
validDate = true;
}
//For months with 31 days
if((month == 1 || month == 2 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day <= 31))
{
validDate = true;
}
//For February
if((month == 2) && (day < 30))
{
//Boolean for valid leap year
boolean validLeapYear = false;
//A leap year is any year that is divisible by 4 but not divisible by 100 unless it is also divisible by 400
if((year % 400 == 0) || ((year % 4 == 0) && (year %100 !=0)))
{
validLeapYear = true;
}
if (validLeapYear == true && day <= 29)
{
validDate = true;
}
else if (validLeapYear == false && day <= 28)
{
validDate = true;
}
}
}
//If the date is valid
if(validDate == true)
{
System.out.println(month + "/" + day + "/" + year + " is a valid date.");
}
else
{
System.out.println("Invalid date!");
}
}
}
The part I'm most concerned with is this:
//For February
if((month == 2) && (day < 30))
{
//Boolean for valid leap year
boolean validLeapYear = false;
//A leap year is any year that is divisible by 4 but not divisible by 100 unless it is also divisible by 400
if((year % 400 == 0) || ((year % 4 == 0) && (year %100 !=0)))
{
validLeapYear = true;
}
if (validLeapYear == true && day <= 29)
{
validDate = true;
}
else if (validLeapYear == false && day <= 28)
{
validDate = true;
}
}
}
As far as I can tell, it looks correct. However, when I input something like 2/29/2011, it returns as a valid date (which it should not, as 2011 was not a leap year). Why is this? What am I missing, or passing over, that causes bad dates to return valid?
if((month == 1 || month == 2 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day <= 31))
This line already catches February.
DateFormat dateFormat = new SimpleDateFormat("yyyy-MMM-dd");
dateFormat.setLenient(false);
String dateAsString = "2011-Feb-29";
Date date = dateFormat.parse(dateAsString); // throws an exception; invalid date
First you're setting validDate to true because month is 2.
Next you're setting validLeapYear to false because it's not a leap year.
(validLeapYear == true && day <= 29) isn't true.
(validLeapYear == false && day <= 28) also isn't true.
Therefore, validDate is still true.