1

Can anyone suggest an example on how to handle invalid inputs, I have got the logic wrong for input from the keyboard. So, I need !myScanner.hasNextInt() or to put that loop in a method which I can reuse for ever.

package dayoftheyear;

import java.util.Scanner;

/**
 *
 * @author abdal
 */
public class DayOfTheYear {

    /**
     * Ask the user to enter a month, day, and year as integers
     * separated by spaces then display the number of the days since the
     * beginning of the year.
     * Don’t forget about leap year.
     * Sample: user inputs ‘3 1 2000’, output is ‘61’.
     * @param args Unused.
     */
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        String enter = "A-z";
        int a=31;
        int b=1;


        boolean dateCheck;
        int month;
        int day;
        int year;

        do {
            System.out.print("Enter a valid month day year separated by spaces");
            if (s.hasNextInt()) {
                month= s.nextInt();
                day=s.nextInt();
                year=s.nextInt();
                if (month >= b && month <= a || day>=b && day<=a || year>=b) {
                    int numberOfDay = countDays(month, day, year);
                    System.out.println(+ month + "/" + day + "/" + year + " is a day number " 
                                + numberOfDay + " of that year");
                    dateCheck = true;
                } else {
                    System.out.println("Enter a valid month day year separated by spaces");
                    dateCheck = false;
                }
            } else {
                System.out.println("Not a date");
                month = 0;
                day=0;
                year=0;
                s.next();
                dateCheck = false;
            }
        } while (!dateCheck);

    /**
     * Get the number of days since the start of the year.
     * Declare a 12 element array and initialize it with the number of
     * days in each month.
     * @param month Month to count from.
     * @param day Day of the month to count to.
     * @param year The year to count from.
     * @return Days since the start of the given year.
     */
    } public static int countDays(int month, int day, int year) {
        int monthLength[] = {
            31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
        };
        int days = 0;
        if (isLeapYear(year) && month > 2) 
            days += 1;
        for (int i = 0; i < month - 1; i++) 
            days += monthLength[i];
        return days += day;
    }

    /**
     * Check if a year is a leap year.
     * @param year Year to check.
     * @return True if the year is a leap year.
     */

        public static boolean isLeapYear(int year) {
            if (year % 4 != 0) return false;
            else if (year % 100 != 0) return true;
            else return year % 400 == 0;
    }   
}
AndiCover
  • 1,724
  • 3
  • 17
  • 38
Abdallah
  • 45
  • 2
  • 8

5 Answers5

2

Replace

if (month >= b && month <= a || day>=b && day<=a || year>=b)

with

if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1)

A sample run after this change:

Enter a valid month day year separated by spaces: 13 1 2000
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 3 32 2000
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 3 1 2
3/1/2 is a day number 60 of that year

Update1: the following condition will hold good also for February

if ((month == 2 && day >= 1 && day <= 28 && year >= 1 && !isLeapYear(year))
        || (month == 2 && day >= 1 && day <= 29 && year >= 1 && isLeapYear(year))
        || (month != 2 && month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1)) 

A sample run:

Enter a valid month day year separated by spaces: 2 29 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 13 2 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 1 32 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 1 2 3
1/2/3 is a day number 2 of that year

Update2: the following code addresses all the issues raised in the comments

int monthLength[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((month == 2 && day >= 1 && day <= 28 && year >= 1 && !isLeapYear(year))
        || (month == 2 && day >= 1 && day <= 29 && year >= 1 && isLeapYear(year))
        || (month != 2 && month >= 1 && month <= 12 && day >= 1 && day <= monthLength[month-1] && year >= 1))

A sample run:

Enter a valid month day year separated by spaces: 2 29 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 13 2 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 1 32 2001
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 6 31 2020
Enter a valid month day year separated by spaces
Enter a valid month day year separated by spaces: 7 31 2020
7/31/2020 is a day number 213 of that year
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • 2 30 2020 should'nt be a valid date (February has 29 days that year) – PajLe Nov 27 '19 at 19:36
  • Now I'm getting an error for 6 31 2020 (June should have 30) Enter a valid month day year separated by spaces 6 31 2020 6/31/2020 is a day number 183 of that year It's very easy to miss something with long expression as that one – PajLe Nov 27 '19 at 20:29
1

Since date format is not subject to change in real world, it should be appropriate to use some hard coding. Dividing the problem into several methods is always recommended.

You could add following methods to your class:

private static boolean validDate(int month, int day, int year) {
    if (year < 1) {
        return false; // no B.C.
    }
    if (month > 1 && month < 13) {
        if (month == 2) { // handle February
            return validFeb(day, year);
        } else if (month % 2 == 1 && month < 8 
                || month % 2 == 0 && month >= 8) { // 31-day months
            return valid31(day);
        } else { // 30 day months
            return valid30(day);
        }
    }

    return false;
}

Validate 30-day months:

private static boolean valid30(int day) {
    if (day > 1 && day < 31) {
        return true;
    }
    return false;
}

Validate 31-day months

private static boolean valid31(int day) {
    if (day > 1 && day < 32) {
        return true;
    }
    return false;
}

Validate February

private static boolean validFeb(int day, int year) {
    if (isLeapYear(year)) {
        if (day > 1 && day < 30) {
            return true;
        }
    } else {
        if (day > 1 && day < 29) {
            return true;
        }
    }

    return false;
}

Then your do-while loop should look something like so:

do {
        System.out.print("Enter a valid month day year separated by spaces\n");
        if (s.hasNextInt()) month = s.nextInt();
            else s.next();
        if (s.hasNextInt()) day = s.nextInt(); 
            else s.next();
        if (s.hasNextInt()) year = s.nextInt(); 
            else s.next();

        int numberOfDaysSinceStart = 0;
        if (validDate(month, day, year)) {
            dateCheck = true;
            numberOfDaysSinceStart = countDays(month, day, year);
            System.out.println(month + "/" + day + "/" + year + " is a day number "
                + numberOfDaysSinceStart + " of that year");
        } else {
            dateCheck = false;
        }
    } while (!dateCheck);
PajLe
  • 791
  • 1
  • 7
  • 21
1

You can add edge cases forever. There is a reason why time-related calculations are nightmare outsourced to libraries written by some poor souls that are paid to try to cover them all. Java has such built in, take a look at java.util.Calendar (Gregorian implementation). You set it to year/month/day, and it will puke out an exception if anything is wrong while trying to get the result.

Calendar c = Calendar.getInstance();
c.set(year, month, day);
try {
    c.getTime();
} catch (Exception e) {
    // wrong date format
}
Vojtěch Kaiser
  • 568
  • 3
  • 15
0

I think the code below can help you, comment if you have any questions.

while(true) {
    try{
        System.out.print("Enter a valid month day year separated by spaces");
        month= s.nextInt();
        day=s.nextInt();
        year=s.nextInt();
        if (month >= 1 && month <= 12 || day>=1 && day<=31 || year>=1) {
            System.out.println(+ month + "/" + day + "/" + year + " is a day number "+ " of that year");
            break;
        } else {
            System.out.println("Enter a valid month day year separated by spaces");
        }
    } catch(InputMismatchException e) {
        System.out.println("Enter a valid month day year separated by spaces");
    }
    s.next();
}
malekiamir
  • 119
  • 2
  • 11
  • How can I make the system to not stop and keep asking the user to enter a valid date if the dates are invalid. The system is stopping after few tries. For example if the user keeps entering a invalid data such as "cat, or or dog 2000", i want the program to continue to ask the user to input a valid date. – Abdallah Nov 27 '19 at 19:27
  • @malekiamir 2 30 2020 should'nt be a valid date (February has 29 days that year) – PajLe Nov 27 '19 at 19:35
  • I'm still getting invalid results for input `2 30 2020` : `Enter a valid month day year separated by spaces 2 30 2020 2/30/2020 is a day number of that year`. This should not be considered a valid date. – PajLe Nov 27 '19 at 19:44
  • @Pajacar123 sorry for that, change the if statement to this : `if ((month >= 1 && month <= 12) && (day>=1 && day<=30) && year>=1990)` – malekiamir Nov 27 '19 at 19:47
0

thanks I updated my program and it is working;

        public static void main(String[] args) {
    Scanner s = new Scanner(System.in);

    int year = 0;
    int month = 0;
    int day = 0;
    boolean dateCheck;
    do {
    System.out.print("Enter a valid month day year separated by spaces\n");
    if (s.hasNextInt()) month = s.nextInt();
        else s.next();
    if (s.hasNextInt()) day = s.nextInt(); 
        else s.next();
    if (s.hasNextInt()) year = s.nextInt(); 
        else s.next();

    int numberOfDaysSinceStart = 0;
    if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1) {
        dateCheck = true;
        numberOfDaysSinceStart = countDays(month, day, year);
        System.out.println(month + "/" + day + "/" + year + " is a day number "
            + numberOfDaysSinceStart + " of that year");
    } else {
        dateCheck = false;
    }
} while (!dateCheck);

/**
 * Get the number of days since the start of the year.
 * Declare a 12 element array and initialize it with the number of
 * days in each month.
 * @param month Month to count from.
 * @param day Day of the month to count to.
 * @param year The year to count from.
 * @return Days since the start of the given year.
 */
} public static int countDays(int month, int day, int year) {
    int monthLength[] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    };
    int days = 0;
    if (isLeapYear(year) && month > 2) 
        days += 1;
    for (int i = 0; i < month - 1; i++) 
        days += monthLength[i];
    return days += day;
}

/**
 * Check if a year is a leap year.
 * @param year Year to check.
 * @return True if the year is a leap year.
 */
public static boolean isLeapYear(int year) {
    if (year % 4 != 0) return false;
    else if (year % 100 != 0) return true;
    else return year % 400 == 0;
}

}

Abdallah
  • 45
  • 2
  • 8
  • 1
    It's not working properly. You should be very careful with dates, you have to consider every case. When you input 2 30 2020, you get results saying it's 61st day of the year. However February doesn't have 30 days. Try my solution. Side note: you should probably not post an answer to your own question unless that was your intention at the beginning – PajLe Nov 27 '19 at 19:49
  • Thanks for your advice, I did use your solution but when I input 2 30 2020 and I'm still getting results saying its 61st day of the year. – Abdallah Nov 27 '19 at 20:29
  • 1
    You probably missed something. I'm getting the correct results. Try copying again. `Enter a valid month day year separated by spaces 2 30 2020 Enter a valid month day year separated by spaces 2 29 2020 2/29/2020 is a day number 60 of that year` – PajLe Nov 27 '19 at 20:33