1+ import java .util .Scanner ;
2+
3+ /*
4+ Adapted by Sleekpanther from SquirrelCoder's initial idea from 29-Jan-17.
5+ Uses arrays, even though they technically aren't introduced until chapter 7. But it simplifies this a lot
6+
7+ 6.34 (Print calendar) Programming Exercise 3.21 uses Zeller's congruence to calculate
8+ the day of the week. Simplify Listing 6.12, PrintCalendar.java, using Zeller's
9+ algorithm to get the start day of the month.
10+
11+
12+ Exercise 3.21 details
13+ (Science: day of the week) Zeller's congruence is an algorithm developed by
14+ Christian Zeller to calculate the day of the week. The formula is:
15+ h=(q + (26(m+1))/10 + k + k/4 + j/4 +5*j)%7
16+ h is the day of the week (0: Saturday, 1: Sunday, 2: Monday, 3: Tuesday, 4: Wednesday, 5: Thursday, 6: Friday).
17+ q is the day of the month.
18+ m is the month (3: March, 4: April, ..., 12: December). January and February are counted as months 13 and 14 of the previous year.
19+ j is the century (i.e. year/100)
20+ k is the year of the century (i.e., year % 100).
21+
22+ Note that the division in the formula performs an integer division. Write a program
23+ that prompts the user to enter a year, month, and day of the month, and
24+ displays the name of the day of the week.
25+ (Hint: January and February are counted as 13 and 14 in the formula, so you need
26+ to convert the user input 1 to 13 and 2 to 14 for the month and change the year to the previous year.)
27+ */
28+ public class PrintCalendar {
29+ public static void main (String []args ) {
30+ Scanner keyboard =new Scanner (System .in );
31+
32+ // get & validate user year
33+ System .out .print ("Enter full year (e.g., 2012): " );
34+ int year =keyboard .nextInt ();
35+ while (!isValidYear (year )) {//validate input
36+ System .out .println ("Invalid Year!" );
37+ System .out .print ("Enter full year (e.g., 2012): " );
38+ year =keyboard .nextInt ();
39+ }
40+
41+ // get & validate user month
42+ System .out .print ("Enter month as number between 1 and 12: " );
43+ int month =keyboard .nextInt ();
44+ while (!isValidMonth (month )) {//validate input
45+ System .out .println ("Invalid Month!" );
46+ System .out .print ("Enter month as number between 1 and 12: " );
47+ month =keyboard .nextInt ();
48+ }
49+
50+
51+ printCalendarHeader (month ,year );// print the calendar header
52+
53+ printFirstDay (month ,year );// print the calendar first day
54+
55+ printCalendarItself (month ,year );// print the calendar itself
56+ }
57+
58+ public static boolean isValidYear (int year ) {
59+ return year >0 ;//might want to check an upper bound, not sure if this formula works for HUGE numbers
60+ }
61+
62+ public static boolean isValidMonth (int month ) {
63+ return month >0 &&month <=12 ;
64+ }
65+
66+ public static void printCalendarHeader (int month ,int year ) {
67+ String []months = {"January" ,"February" ,"March" ,"April" ,"May" ,"June" ,"July" ,"August" ,"Septemter" ,"October" ,"November" ,"December" };
68+
69+ System .out .print ("\t \t " +months [month -1 ]+"\t " );//access the month array with a -1 offset since arrays count from 0
70+ System .out .println (year );
71+ System .out .println ("---------------------------" );
72+
73+ System .out .println ("Sun\t Mon\t Tue\t Wed\t Thu\t Fri\t Sat" );
74+ }
75+
76+ public static void printFirstDay (int month ,int year ) {
77+ int firstDay =dayOfWeek (1 ,month ,year );//calculate the 1st day
78+
79+ String leadingTabs ="1" ;//Holds any leading tabs to align 1st row of numbers in a calendar. This takes care of firstDay=1
80+
81+ //cases for firstDay between 2 & 6 (adds a "\t" at the beginning of the string each iteration)
82+ //Loop starts from 1 since we want 1 less tab than the value of firstDay (firstDay=1 is 0 tabs, firstDay=2 is 1 tab, firstDay=3 is 2 tabs, firstDay=4 is 3 tabs, firstDay=5 is 4 tabs)
83+ for (int i =1 ;i <firstDay ;i ++){
84+ leadingTabs ="\t " +leadingTabs ;
85+ }
86+ if (firstDay ==0 ){//reset it & ignore what the loop did if it's 0. THIS IS A SPECIAL CASE. We want 6 tabs
87+ leadingTabs ="\t \t \t \t \t \t 1" ;
88+ }
89+
90+ System .out .print (leadingTabs +"\t " );
91+ }
92+
93+ public static void printCalendarItself (int month ,int year ) {
94+ // find out the last day of that month
95+ // whether it's 28/29/30/31 days
96+ int lastDayOfMonth =lastDayOfMonth (month ,year );
97+
98+ // print the calendar itself
99+ for (int i =2 ;i <=lastDayOfMonth ;i ++) {
100+ int printedDay =dayOfWeek (i ,month ,year );
101+ if (printedDay ==1 ) {
102+ System .out .println ();
103+ }
104+ System .out .print (i +"\t " );
105+ }
106+ }
107+
108+ //Implement Zeller's Algorithm
109+ public static int dayOfWeek (int dayOfMonth ,int month ,int year ) {
110+ if (month ==1 ||month ==2 ) {
111+ month =month +12 ;
112+ year --;
113+ }
114+ int q ,m ,j ,k ;
115+ q =dayOfMonth ;
116+ m =month ;//adjusted month (corrected for January & February being 13 & 14 respectively)
117+ j =year /100 ;//century
118+ k =year %100 ;//year of the century
119+ int dayOfTheWeek = (q + (26 *(m +1 ) /10 ) +k +k /4 +j /4 + (5 *j )) %7 ;//performs integer division where appropriate (like the Algorithms wants)
120+ return dayOfTheWeek ;
121+ }
122+
123+ public static boolean isLeapYear (int year ) {
124+ return year %400 ==0 || (year %4 ==0 &&year %100 !=0 );
125+ }
126+
127+ public static int lastDayOfMonth (int month ,int year ) {
128+ int lastDayOfMonth ;
129+ if (month ==1 ||month ==3 ||month ==5 ||month ==7 ||month ==8 ||month ==10 ||month ==12 ) {
130+ lastDayOfMonth =31 ;
131+ }else if (month ==2 ) {
132+ if (isLeapYear (year )) {
133+ lastDayOfMonth =29 ;
134+ }else {
135+ lastDayOfMonth =28 ;
136+ }
137+ }else {
138+ lastDayOfMonth =30 ;
139+ }
140+ return lastDayOfMonth ;
141+ }
142+
143+ }