2

I am trying to write a program in Java (this is a school assignment that tells you what day of the week a certain date is. (The date should be written on the form yyyy-mm-dd.) I thought I had come up with a solution with the code below, but then I found an error.

When you run the code, and type in 1999-12-31 in the dialog, the program tells you that the entered date (1999-12-31) is a Friday. But when you type in the date 2000-01-01 (which is one day after 1999-12-31), the program tells you that the day is a Sunday! What happened with Saturday? A similar problem happens when you type in 2000-02-29 and 2000-03-01, they both give Wednesday as an answer!

What I have yet noticed, this error appears only when you enter a date between 2000-01-01 and 2000-02-29. I would be very grateful if someone could please help me to find the cause of the error and to solve the problem!

import static javax.swing.JOptionPane.*;
import static java.lang.Math.*;

public class DateCalc {

    // Here, between the DateCalc class declaration and the main method, several methods used in the program are
    // constructed.

    // The method isLeapYear tests whether the entered year is a leap year or not.
    private static boolean isALeapYear(int year)    {
        // If the year is a multiple of 4 and not a multiple of 100, or a multiple of 400, then it is a leap year.
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)  {
            return true;
        }
        else {
            return false;
        }
    }

    // A method that tests whether a given string is written as a valid date.
    private static boolean isAValidDate(int year, int month, int day)   {
        int maxValidYear = 9999;
        int minValidYear = 1754;
        if (year > maxValidYear || year < minValidYear) {
            return false;
        }
        if (month < 1 || month > 12)    {
            return false;
        }
        if (day < 1 || day > 31)    {
            return false;
        }
        // Handle the February Month
        if (month == 2) {
            if (isALeapYear(year)) {
                return (day <= 29); // This statement is true if the value of the day is less than or equal to 29 if the month is February within a leap year.
                // Otherwise the statement is false and the method will return the boolean value false.
            }
            else {
                return (day <= 28); // This statement is true if the value of the day is less than or equal to 28 if the month is February within a non-leap year.
                // Otherwise the statement is false and the method will return the boolean value false.
            }
        }
        // Month of April, June, September and November must have number of days less than or equal to 30.
        if (month == 4 || month == 6 || month == 9 || month == 11)  {
            return (day <= 30);
        }
        return true;
    }

    // A method that calculates the day number within the year.
    private static int dayNumberWithinYear(int year, int month, int day)    {
        // An array which stores the number of days in the different months (when the year is not a leap year).
        // (Index 0 is the number of days in January, index 1 is the number of days in February, etc.)
        int[] monthStructure = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

        // If the entered year is a leap year, then the monthStructure array will be initialized with an extra day in February, i.e the leap day.
        if (isALeapYear(year))  {
            monthStructure[1] = 29;
        }

        int sumDaysInPreviousMonths = 0;
        int daysInTheCurrentMonth = day;
        int dayNumber = 0;

        // Loops through all the months (index 0 is January, index 1 is February, etc.).
        for (int i = 0; i < month - 1; i++) {
            sumDaysInPreviousMonths += monthStructure[i];
        }

        dayNumber = sumDaysInPreviousMonths + daysInTheCurrentMonth;

        return dayNumber;
    }

    // A method that decides the day of the week of an entered date.
    private static void weekDay(int year, int month, int day)   {
        // The number of days that have passed since January 1, 1754, excluding the days of the entered year and
        // excluding the leap days.
        int sumDaysInOrdinaryYears = (year - 1754) * 365;
        int sumLeapDaysInLeapYears = 0;

        // Suppose the entered year is n. The for-loop goes through all the years from year n-1 to year 1754, and
        // checks if the current year in the loop is a leap year. The number of leap years between year 1754 and n-1
        // is equal to the number of days that will get added (beside from the days in ordinary years) to the total
        // days from January 1, 1754 to the entered date.
        for (; year > 1754; year -= 1)  {
            if (isALeapYear(year))  {
                sumLeapDaysInLeapYears += 1;
            }
        }
        // The sum of all days from year 1754 to year n-1 (if the entered year is n), is equal to the sum of days in
        // the ordinary years and the leap days in the years.
        int sumDaysInEveryYearExcludingTheEntered = sumDaysInOrdinaryYears + sumLeapDaysInLeapYears;
        int sumDaysInTotalYears = sumDaysInEveryYearExcludingTheEntered + dayNumberWithinYear(year, month, day);
        int weekDay = sumDaysInTotalYears % 7;

        if (weekDay == 0)   {
            showMessageDialog(null, "The date is a monday.");
        }
        else if (weekDay == 1)  {
            showMessageDialog(null, "The date is a tuesday.");
        }
        else if (weekDay == 2)  {
            showMessageDialog(null, "The date is a wednesday.");
        }
        else if (weekDay == 3)  {
            showMessageDialog(null, "The date is a thursday.");
        }
        else if (weekDay == 4)  {
            showMessageDialog(null, "The date is a friday.");
        }
        else if (weekDay == 5)  {
            showMessageDialog(null, "The date is a saturday.");
        }
        // If weekDay == 6
        else    {
            showMessageDialog(null, "The date is a sunday.");
        }
    }

    public static void main(String[] args)  {
        // This is step 3 in the laboratory instruction.
        while (true)    {
            String date = showInputDialog("Please, enter a date on the form yyyy-mm-dd");

            // If the user clicks 'Cancel' or clicks 'OK' when the dialog box is empty, the program will exit.
            if (date == null || date.length() == 0) {
                break;
            }
            int y = Integer.parseInt(date.substring(0,4));
            int m = Integer.parseInt(date.substring(5,7));
            int d = Integer.parseInt(date.substring(8));
            if (!isAValidDate(y, m, d)) {
                showMessageDialog(null, "Error! The entered date is invalid. " +
                        " Please enter a valid date on the form yyyy-mm-dd");
            }
            else {
                weekDay(y, m, d);
            }
        }
    }
}
Eric J
  • 29
  • 2
  • 2
    Did you try to debug the code in the IDE? – Hari Prasad Feb 11 '19 at 15:11
  • 2
    This is a good opportunity to [learn how to debug](https://stackoverflow.com/questions/3974230/how-to-learn-debugging) your program. Are you using an IDE, such as Eclipse or IntelliJ? Learn how to step through the code line by line to discover what exactly it's doing, and where the mistake is. – Jesper Feb 11 '19 at 15:11
  • 2000 was a leap year. Debug you code and check if it add a leap day for the current year. – jhamon Feb 11 '19 at 15:42
  • While this may be an assignment that doesn’t allow you to use the built-in `LocalDate` class, it’s still worth mentioning that for production code one would certainly do just that and not code one’s own logic. – Ole V.V. Feb 11 '19 at 15:43

2 Answers2

2

Instead of asking us to debug through your entire code, perhaps consider LocalDate to get the desired result:

LocalDate ldt = LocalDate.parse("1999-12-31");
System.out.println(ldt.getDayOfWeek());
LocalDate ldt2 = LocalDate.parse("2000-01-01");
System.out.println(ldt2.getDayOfWeek());

Output:

FRIDAY

SATURDAY

Community
  • 1
  • 1
achAmháin
  • 4,176
  • 4
  • 17
  • 40
  • 1
    For production code this is an excellent suggestion. For the school assignment in the question — it depends on whether it’s allowed, which is not clear from the question. – Ole V.V. Feb 11 '19 at 15:50
2

The Problem is with finding the number of leap year. Your logic is counting the year 2000 also. The number of leap years should be same for 1999-12-31 and 2000-01-01. You need to consider year 2000 only if the month is greater than February. Increment the sumLeapDaysInLeapYears only if the input date is greater than Feb 28th

Hari Prasad
  • 304
  • 1
  • 6
  • 2
    I believe you’ve spotted the bug. Since finding the number of the day in the year does correctly take leap year into account, I believe that the count of leap years should *never* include the current year, no matter if the date is before or after February. But the asker can conduct tests to veryfy. – Ole V.V. Feb 11 '19 at 15:48