1

This is homework.

I am trying to find every occurrence of a Sunday landing on the first of a month between Jan 1 1900 (which we are assuming was a Monday) and Dec 31 of a year that the user inputs. The calendar extension is off-limits.

I am returning dates in the correct format, but they do not match up with the example code our instructor provided.
In the given example, an input of 1902 should return:
1 Apr 1900
1 Jul 1900
1 Sep 1901
1 Dec 1901
1 Jun 1902

For 1902, my code returns:
1 Mar 1900
1 Jan 1901
1 Apr 1901
1 May 1901
1 Feb 1902
1 Jun 1902
1 Jul 1902

import java.util.Scanner;


public class Sundays {

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

    System.out.print("Enter the ending year: ");
    int userInputYear = reader.nextInt();

    int[] orderedLengthOfMonthsArray = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    String[] orderedNamesOfMonthsArray = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    int month = 0;
    int dayOfWeek = 1; // initialized to MONDAY Jan 1, 1900 -- Sunday would be #7
    int dayOfMonth = 1;


    for (int year = 1900; year <= userInputYear; year++) {

        for (month = 0; month < orderedLengthOfMonthsArray.length; month++) {


            for (dayOfMonth = 1; dayOfMonth <= orderedLengthOfMonthsArray[month]; dayOfMonth++) {

                dayOfWeek++;

                if (dayOfMonth == 1 && dayOfWeek == 7) {
                    System.out.println(dayOfMonth + " " + orderedNamesOfMonthsArray[month] + " " + year);
                }

                if (dayOfWeek == 8) {
                    dayOfWeek = 1;
                }                   
            }
        }
    }
}  
}
Matt Voda
  • 131
  • 1
  • 2
  • 9

4 Answers4

3

Swap the if statement and the increase of dayOfWeek.

        for (dayOfMonth = 1; dayOfMonth <= orderedLengthOfMonthsArray[month]; dayOfMonth++) {
            if (dayOfMonth == 1 && dayOfWeek == 7) {
                System.out.println(dayOfMonth + " " + orderedNamesOfMonthsArray[month] + " " + year);
            }

            dayOfWeek++;

            if (dayOfWeek == 8) {
                dayOfWeek = 1;
            }                   
        }

When you are in the dayOfMonth for loop, you already have the correct day of the week (initially Monday, Jan 1st, 1900), so if you first increase it, then the check afterwards would be incorrect.

yasen
  • 1,250
  • 7
  • 13
  • Interesting — this solved it. Thank you for the helpful explanation as well. Order really is everything! – Matt Voda Feb 20 '14 at 02:54
1
if (dayOfWeek == 7) {
    dayOfWeek = 1;
}  

So your week has 6 days? I think you should either reset to zero or reset when dayOfWeek is 8.

exception1
  • 1,239
  • 8
  • 17
1

Someone mentioned Joda-Time magic… So here's my solution using Joda-Time 2.3.

While the question (a homework assignment) forbade the use of added libraries…

  • The comparison may be enlightening.
  • The student should soon learn that the java.util.Date & Calendar classes are notoriously troublesome and should be avoided for real-world work. They are supplanted in Java 8 by the new java.time.* package which is inspired by Joda-Time and defined by JSR 310.

My example code uses LocalDate which should only be used if your are absolutely certain that you don't care about (a) time of day, and (b) time zones. I do not usually recommend this approach as naïve programmers who believe they need neither time nor zone often turn out to be mistaken.

// Start
LocalDate start = new LocalDate( 1900, 1, 1 );

// Stop
// Using "half-open" comparison. We care about December 31 of specified year, but we will test for January 1 of year after.
String input = "1930";
int year = Integer.valueOf( input );
year = ( year + 1 );  // Add one to get to next year, for "half-open" approach.
LocalDate stop = new LocalDate( year, 1, 1 );

// Collect each LocalDate where the first of the month is a Sunday.
java.util.List<LocalDate> localDates = new java.util.ArrayList<LocalDate>();
LocalDate localDate = start;
do {
    if ( localDate.getDayOfWeek() == DateTimeConstants.SUNDAY ) { // Comparing 'int' primitive values.
        localDates.add( localDate ); // Collect this LocalDate instance.
    }
    localDate = localDate.plusMonths( 1 ); // Move on to next month. Joda-Time is smart about various month-ends and leap-year.
} while ( localDate.isBefore( stop ) ); // "Half-Open" means test "<" rather than "<=".

Dump to console…

System.out.println( "The First-Of-The-Month days that are Sundays from " + start + " (inclusive) to " + stop + " (exclusive):" );
System.out.println( localDates );
The First-Of-The-Month days that are Sundays from 1900-01-01 (inclusive) to 1931-01-01 (exclusive):
[1900-04-01, 1900-07-01, 1901-09-01, 1901-12-01, 1902-06-01, 1903-02-01, 1903-03-01, 1903-11-01, 1904-05-01, 1905-01-01, 1905-10-01, 1906-04-01, 1906-07-01, 1907-09-01, 1907-12-01, 1908-03-01, 1908-11-01, 1909-08-01, 1910-05-01, 1911-01-01, 1911-10-01, 1912-09-01, 1912-12-01, 1913-06-01, 1914-02-01, 1914-03-01, 1914-11-01, 1915-08-01, 1916-10-01, 1917-04-01, 1917-07-01, 1918-09-01, 1918-12-01, 1919-06-01, 1920-02-01, 1920-08-01, 1921-05-01, 1922-01-01, 1922-10-01, 1923-04-01, 1923-07-01, 1924-06-01, 1925-02-01, 1925-03-01, 1925-11-01, 1926-08-01, 1927-05-01, 1928-01-01, 1928-04-01, 1928-07-01, 1929-09-01, 1929-12-01, 1930-06-01]
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Nice. Don't forget that you can format the output with `localDate.toString("dd MMM yyyy");` as for timezones, I would use [DateMidnight](http://joda-time.sourceforge.net/apidocs/org/joda/time/DateMidnight.html) or even [DateTime](http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html) + `withTimeAtStartOfDay`. Joda is so cool that you can change the type and it will work. – Anthony Accioly Feb 20 '14 at 15:35
  • @AnthonyAccioly Valid points, except that `DateMidnight`. The "midnight" classes and methods are no longer recommended by the Joda-Time team. That [`withTimeAtStartOfDay`](http://www.joda.org/joda-time/apidocs/org/joda/time/DateTime.html#withTimeAtStartOfDay()) method was added in v2.3 to supplant the midnight-stuff. See [this answer by Alex](http://stackoverflow.com/a/19048833/642706) for doc. – Basil Bourque Feb 21 '14 at 03:51
0

Just for fun, while you have explicitly mentioned not to use Calendar, here is how we could do it:

public static List<Date> mondaysFirst(int firstYear, int lastYear) {
    final List<Date> dates = new ArrayList<>();
    final Calendar c1 = Calendar.getInstance(Locale.US);
    c1.set(firstYear, 0, 1, 0, 0, 0);
    final Calendar c2 = Calendar.getInstance(Locale.US);
    c2.set(lastYear, 11, 31, 23, 59, 59);

    while (c1.before(c2)) {
        final int dayOfTheWeek = c1.get(Calendar.DAY_OF_WEEK);
        // is sunday
        if (dayOfTheWeek == 1) {
            dates.add(c1.getTime());    
        }
        c1.add(Calendar.MONTH, 1);
    }

    return dates;
}

And to print the results:

final List<Date> dates = mondaysFirst(1900, 1902);
final SimpleDateFormat sf = new SimpleDateFormat("dd MMM yyyy");
for (Date date: dates) {
    System.out.println(sf.format(date));
}

Working Example.


I'm sure that there is some Joda-Time magic to make this even shorter.

Anthony Accioly
  • 21,918
  • 9
  • 70
  • 118