/ TRAINING

Calender 2

실습

코드스쿼드 자바 플레이그라운드 캘린더 만들기


0. 목차



6. 가상의 달력 찍기1

7. 가상의 달력 찍기2 - 윤년

8. 시작일 설정 달력 찍기

9. 진짜 달력 자동으로 찍기



1. 가상의 달력 찍기1


▶ Mission.

▷ 월을 입력하면 해당월의 달력을 출력한다.

▷ 달력은 모양은 1단계에서 작성한 모양으로 만든다.

▷ 1일은 일요일로 정해도 무방하다.

▷ -1을 입력받기 전까지 반복 입력받는다.

▷ 프롬프트를 출력한다.

월을 입력하세요.
> 3
      
--------------------
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
월을 입력하세요.
> -1
Bye~

혼자 Mission 해보기

package baek.calender;

import java.util.Scanner;

public class Calender {

	public static final int[] maxDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	
	public int maxDaysOfMonth(int month) {
		return maxDays[month - 1];
	}
	
	public static void main(String[] args) {
		
		String PROMPT = "cal> ";
		Scanner scanner = new Scanner(System.in);
		Calender cal = new Calender();
		
		while(true) {
			
			System.out.printf("월을 입력하세요.\n");
			System.out.print(PROMPT);
			int month = scanner.nextInt();
			
			String b = "";
			String i = "31";
			String j = "30 ";
			String t = "29 ";
			String k = " 28 ";
			
			if(month == 1) {
				b = t + j + i;
			} else if(month == 2) {
				b = "";
			} else if(month == 3) {
				b = t + j + i;
			} else if(month == 5) {
				b = t + j + i;
			} else if(month == 7) {
				b = t + j + i;
			} else if(month == 8) {
				b = t + j + i;
			} else if(month == 10) {
				b = t + j + i;
			} else {
				b = t + j;
			}
			
			System.out.println("일 월 화 수 목 금 토");
			System.out.println("---------------------");
			System.out.println(" 1  2  3  4  5  6  7");
			System.out.println(" 8  9 10 11 12 13 14");
			System.out.println("15 16 17 18 19 20 21");
			System.out.println("22 23 24 25 26 27" + k);
			System.out.println(b);
			
			if(month == -1) {
				break;
			}
			
			if(month > 12) {
				continue;
			}
			
			System.out.printf("\n%d월은 %d일까지 있습니다.\n\n", month, cal.maxDaysOfMonth(month));
		}
		
		System.out.println("Have a nice day!");
		scanner.close();
	}
}
월을 입력하세요.
cal> 10

      
---------------------
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28 
29 30 31

10월은 31일까지 있습니다.

월을 입력하세요.
cal> -1

      
---------------------
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28 
29 30 
Have a nice day!

해설 보고 Mission 해보기 - 1

▷ Prompt 클래스 생성 - 기능분리

package baek.calender;

import java.util.Scanner;

public class Prompt {
	
	private final static String PROMPT = "cal> ";
	
	public void runPrompt() {
		Scanner scanner = new Scanner(System.in);
		Calender cal = new Calender();
		
		int month = 1;

		while(true) {
			System.out.println("월을 입력하세요.");
			System.out.print(PROMPT);
			month = scanner.nextInt();
			
			if(month == -1) {
				break;
			}
			
			if(month > 12) {
				continue;
			}
			System.out.printf("%d월은 %d일 까지 있습니다.\n\n", month, cal.maxDaysOfMonth(month));
		}	
		System.out.println("repeat 종료");
		scanner.close();
	}

	public static void main(String[] args) {
		Prompt p = new Prompt();
		p.runPrompt();
	}
}
월을 입력하세요.
cal> 5
5월은 31 까지 있습니다.

월을 입력하세요.
cal> 2
2월은 28 까지 있습니다.

월을 입력하세요.
cal> 3
3월은 31 까지 있습니다.

월을 입력하세요.
cal> -1
repeat 종료

기능별로 분리하는 습관!

해설 보고 Mission 해보기 - 2

▷ 실제 달력모양 출력


일수 출력이 아닌 달력모양 출력이므로
Calender 클래스에 있는 printCalender 메서드를
Prompt 클래스에서 호출

//Calender
public void printCalender(int year, int month) {
		System.out.printf("   <<%4d %3d>>\n", year, month);
		System.out.println("SU MO TU WE TH FR SA");
		System.out.println("--------------------");
		System.out.println(" 1  2  3  4  5  6  7");
		System.out.println(" 8  9 10 11 12 13 14");
		System.out.println("15 16 17 18 19 20 21");
		System.out.println("22 23 24 25 26 27 28");
	}
//Prompt
cal.printCalender(2021, month);
package baek.calender;

import java.util.Scanner;

public class Prompt {
	
	private final static String PROMPT = "cal> ";
	
	public void runPrompt() {
		Scanner scanner = new Scanner(System.in);
		Calender cal 	= new Calender();
		
		int month = 1;

		while(true) {
			System.out.println("월을 입력하세요.");
			System.out.print(PROMPT);
			month = scanner.nextInt();
			
			if(month == -1) {
				break;
			}
			
			if(month > 12) {
				continue;
			}
			cal.printCalender(2021, month);
		}	
		System.out.println("repeat 종료");
		scanner.close();
	}

	public static void main(String[] args) {
		Prompt p = new Prompt();
		p.runPrompt();
	}
}
월을 입력하세요.
cal> 3
   <<2021   3>>
SU MO TU WE TH FR SA
--------------------
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
월을 입력하세요.
cal> 

해설 보고 Mission 해보기 - 3

▷ 실제 달력모양 출력

▷ 같은모양 다른코딩 - 반복문

public void printCalender(int year, int month) {
		System.out.printf("   <<%4d %3d>>\n", year, month);
		System.out.println("SU MO TU WE TH FR SA");
		System.out.println("--------------------");
		System.out.println(" 1  2  3  4  5  6  7");
		System.out.println(" 8  9 10 11 12 13 14");
		System.out.println("15 16 17 18 19 20 21");
		System.out.println("22 23 24 25 26 27 28");
	}
	public void printCalender(int year, int month) {
		System.out.printf("   <<%4d %3d>>\n", year, month);
		System.out.println("SU MO TU WE TH FR SA");
		System.out.println("--------------------");
		
		int maxDays = maxDaysOfMonth(month);
		
		for(int i = 1; i <= maxDays; i++) {
			System.out.printf("%3d", i);
			
			if(i % 7 == 0) {
				System.out.println();
			}
		}
		System.out.println();
	}
월을 입력하세요.
cal> 3
   <<2021   3>>
SU MO TU WE TH FR SA
--------------------
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28
 29 30 31
월을 입력하세요.
cal> 2
   <<2021   2>>
SU MO TU WE TH FR SA
--------------------
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28

월을 입력하세요.
cal> -1
repeat 종료



2. 가상의 달력 찍기2 - 윤년


▶ Mission.

▷ 윤년의 경우 29일까지 찍는 로직을 구현


윤년
1.서력 기원 연수가 4로 나누어 떨어지는 해는 윤년으로 한다.
2.서력 기원 연수가 4, 100으로 나누어 떨어지는 해는 평년으로 한다.
3.서력 기원 연수가 4, 100, 400으로 나누어 떨어지는 해는 윤년으로 둔다.

  • 윤년이 되는 경우
    1) 4 ÷ 년도 == 0
    2) 4 ÷ 년도 == 0 && 400 ÷ 년도 == 0
    3) 4 ÷ 년도 == 0 && 400 ÷ 년도 == 0 && 100 ÷ 년도 == 0
  • 4 ÷ 년도 == 0 && 100 ÷ 년도 == 0
    이건 윤년 아님! 이건 평년!

해설 보고 Mission 해보기

▷ 윤년의 최대일수를 구하는 메서드 추가생성

▷ 윤년을 계산하는 메서드 생성

▷ month 뿐만 아니라 year 까지 입력받기

//Calender
package baek.calender;

public class Calender {
	
	public static final int[] MAX_DAYS 		= {31,28,31,30,31,30,31,31,30,31,30,31};
	public static final int[] LEAP_MAX_DAYS	= {31,29,31,30,31,30,31,31,30,31,30,31};
	
	public int maxDaysOfMonth(int year, int month) {
		if(isLeapYear(year)) {
			return LEAP_MAX_DAYS[month - 1];
		}else {
			return MAX_DAYS[month - 1];
		}
	}
	
	public boolean isLeapYear(int year) {
		if(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
			return true;
		}else {
			return false;
		}	
	}
	
	public void printCalender(int year, int month) {
		System.out.printf("   <<%4d %3d>>\n", year, month);
		System.out.println("SU MO TU WE TH FR SA");
		System.out.println("--------------------");
		
		int maxDays = maxDaysOfMonth(year, month);
		
		for(int i = 1; i <= maxDays; i++) {
			System.out.printf("%3d", i);
			
			if(i % 7 == 0) {
				System.out.println();
			}
		}
		System.out.println();
	}
}
//Prompt
package baek.calender;

import java.util.Scanner;

public class Prompt {
	
	public void runPrompt() {
		Scanner scanner = new Scanner(System.in);
		Calender cal 	= new Calender();
		
		int month 	= 1;
		int year 	= 1;

		while(true) {
			System.out.println("년을 입력하세요.");
			System.out.print("YEAR> ");
			year = scanner.nextInt();
			System.out.println("월을 입력하세요.");
			System.out.print("MONTH> ");
			month = scanner.nextInt();
			
			if(month == -1) {
				break;
			}
			if(month > 12) {
				continue;
			}
			cal.printCalender(year, month);
		}	
		System.out.println("repeat 종료");
		scanner.close();
	}

	public static void main(String[] args) {
		Prompt p = new Prompt();
		p.runPrompt();
	}
}
년을 입력하세요.
YEAR> 20
월을 입력하세요.
MONTH> 2
   <<  20   2>>
SU MO TU WE TH FR SA
--------------------
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28
 29
년을 입력하세요.
YEAR> 21
월을 입력하세요.
MONTH> 2
   <<  21   2>>
SU MO TU WE TH FR SA
--------------------
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28

년을 입력하세요.
YEAR> 10000
월을 입력하세요.
MONTH> 2
   <<10000   2>>
SU MO TU WE TH FR SA
--------------------
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28
 29
년을 입력하세요.
YEAR> -1
월을 입력하세요.
MONTH> -1
repeat 종료
[알게 된 점]

참고

1. boolean

데이터 타입
ture/false 값을 가지는 데이터 타입

2. %4d

printf에서 %d는 정수
%4d는 정수가 4칸 차지한다는 뜻
년도는 현재 통상적으로 4자리 수 ex)2021년
%4d로 설정 해 두고 21을 넣으면 __21 이렇게 나옴(__은 빈자리)

3. &&

A && B
A and B
A 와 B == true
둘 다 true면 true

4. ||

A || B
A or B
A 아니면 B == true
둘 중 하나 true면 true



3. 시작일 설정 달력 찍기


▶ Mission.

▷ 월을 입력받는다.

▷ 1일의 요일을 입력받는다.

▷ 출력한다.

년도를 입력하세요.
YEAR> 2017
달을 입력하세요.
MONTH> 3
첫번째 요일을 입력하세요. (SU, MO, WE, TH, FR, SA)
WEEKDAY> WE

    <<2017  3>>
 SU MO TU WE TH FR SA
---------------------
           1  2  3  4
  5  6  7  8  9 10 11
  ...

▶ 해설보고 Mission 해보기

//Calendar
public class Calendar {

	public int weekday_Start(String weekday_Str) {

		if (weekday_Str.equals("SU")) {
			return 0;
		} else if (weekday_Str.equals("MO")) {
			return 1;
		} else if (weekday_Str.equals("TU")) {
			return 2;
		} else if (weekday_Str.equals("WE")) {
			return 3;
		} else if (weekday_Str.equals("TH")) {
			return 4;
		} else if (weekday_Str.equals("FR")) {
			return 5;
		} else if (weekday_Str.equals("SA")) {
			return 6;
		} else {
			return 0;
		}

	}

	private static final int[] maxDayOfMonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	private static final int[] leap_maxDayOfMonth = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	public int get_maxDayOfMonth(int year, int month, int weekday) {

		if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
			return leap_maxDayOfMonth[month];
		}

		return maxDayOfMonth[month];
	}

	public void printCalendar(int year, int month, int weekday) {

		int days = get_maxDayOfMonth(year, month, weekday);
		int count = 7 - weekday;
		int delim = count < 7 ? count : 0;

		System.out.println(" SU MO TU WE TH FR SA");
		System.out.println("---------------------");

		for (int i = 0; i < weekday; i++) {
			System.out.print("   ");
		}

		for (int i = 1; i <= days; i++) {

			System.out.printf("%3d", i);

			if (i % 7 == delim) {
				System.out.println();
			}
		}
		System.out.printf("\n\n");
	}

	public static void main(String[] args) {

	}
}
//Prompt
import java.util.Scanner;

public class Prompt {

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

		int year = 0;
		int month = 0;
		int weekday = 0;

		while (true) {

			System.out.println("년도를 입력하세요.(EXIT : -1)");
			System.out.print("YEAR> ");
			year = scanner.nextInt();

			if (year == -1) {
				break;
			}

			System.out.println("월을 입력하세요.");
			System.out.print("MONTH> ");
			month = scanner.nextInt();

			if (month > 12 || month < 1) {
				System.out.println("입력오류");
				System.out.println();
				continue;
			}

			System.out.println("요일을 입력하세요.(SU MO TU WE TH FR SA)");
			System.out.print("DAY> ");
			String weekday_Str = scanner.next();
			weekday = cal.weekday_Start(weekday_Str);

			cal.printCalendar(year, month, weekday);
		}

		System.out.println("종료");
		scanner.close();
	}
}
년도를 입력하세요.(EXIT : -1)
YEAR> 2020
월을 입력하세요.
MONTH> 5
요일을 입력하세요.(SU MO TU WE TH FR SA)
DAY> MO
 SU MO TU WE TH FR SA
---------------------
     1  2  3  4  5  6
  7  8  9 10 11 12 13
 14 15 16 17 18 19 20
 21 22 23 24 25 26 27
 28 29 30 31

년도를 입력하세요.(EXIT : -1)
YEAR> 
[시작일 설정 방법]

월마다 시작하는 요일이 다 다름
그 때 마다 달력모양에서는 시작하는 부분을 맞춰줘야 함
맞춰주기 위해서는 앞부분과 뒷부분을 생각해야함

앞부분 - 띄어쓰기

일요일은 띄어쓰기 없음
월요일은 띄어쓰기 한 번
화요일은 띄어쓰기 두 번
이런 식으로 맞춰주어야 함

이 설정을 weekday_Start에서 해 줌
weekday_Start 이걸 불러다가 쓰면
앞부분 띄어쓰기 설정은 완료

weekday 설정 경로
weekday_Str로 시작요일 입력받음 - SU MO TU WE TH FR SA
cal.weekday_Start(weekday_Str)
→ 요일에 해당하는 return 값을 받음
weekday에 담음

for (int i = 0; i < weekday; i++) {
System.out.print("   ");
}

weekday만큼 띄어쓰기 세 칸을 띄어쓰기 해 줌

for (int i = 1; i <= days; i++) {
System.out.printf("%3d", i);
}

해당 월의 일수를 3칸에 걸쳐 적어 줌

뒷부분 - 줄바꿈

앞부분을 띄어쓰기 해 놓으면 뒷부분은 자동 줄바꿈 되나?
안 됨

그래서 그것도 설정을 해 주어야 함

줄바꿈은 숫자 7개를 쓰는 것으로 설정 해 둠
그런데 첫 줄은 띄어쓰기 설정하면 일요일 제외 숫자 7개가 안됨
그래서 7에서 띄어쓰기 한 수만큼 빼준 수를 기준으로 줄바꿈 설정 해야함
띄어쓰기 한 수 = weekday
7 - weekday를 설정

int count = 7 - weekday;<br/>

※ 근데 일요일은 7 - 0 이라서 7이 됨
이런 경우는 줄바꿈을 아예 안하는 것으로 인식 됨
일요일을 위해 delim을 하나 만들기

int delim = count < 7 ? count : 0;<br/>

=

delim
=
if (count < 7)  return count;
else  return 0;

delim 설정을 해 주고
일수(i)를 7로 나눈 나머지가 delim과 같다면 줄바꿈 해라!

if (i % 7 == delim) {
  System.out.println();
}

이렇게 작성을 해 주면 뒷 부분 줄바꿈도 설정 됨



4. 진짜 달력 자동으로 찍기


▶ Mission.

▷ 년도와 월만 입력받는다.

▷ 진짜 캘린더에서 나오는 달력과 똑같은 모양의 달력을 출력한다.

년도를 입력하세요.
> 2017
월을 입력하세요.
> 6

2017 6
      
       1  2  3
4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

년도를 입력하세요.
> -1
Bye  

▶ 해설 보고 Mission 해보기

//Prompt
import java.util.Scanner;

public class Prompt {

	public void runPrompt() {

		Scanner scanner = new Scanner(System.in);
		Calendar cal = new Calendar();

		int year = 0;
		int month = 0;

		while (true) {

			System.out.println("년도를 입력하세요.(EXIT : -1)");
			System.out.print("YEAR> ");
			year = scanner.nextInt();

			if (year == -1) {
				break;
			}

			System.out.println("월을 입력하세요.");
			System.out.print("MONTH> ");
			month = scanner.nextInt();
			System.out.println();

			if (month > 12 || month < 1) {
				System.out.println("입력오류");
				System.out.println();
				continue;
			}

			cal.printCalendar(year, month);
		}

		System.out.println("종료");
		scanner.close();
	}

	public static void main(String[] args) {

		Prompt prt = new Prompt();

		prt.runPrompt();
	}
}
//Calendar
public class Calendar {

	private static final int[] maxDayOfMonth 
			= { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	private static final int[] leap_maxDayOfMonth 
			= { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

	public boolean isLeapYear(int year) {
		
		if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
			return true;
		} else {
			return false;
		}
	}
	
	public int get_maxDayOfMonth(int year, int month) {

		if (isLeapYear(year)) {
			return leap_maxDayOfMonth[month];
		}

		return maxDayOfMonth[month];
	}

	public void printCalendar(int year, int month) {

		System.out.printf("     -%4d년 %d월-\n", year, month);
		System.out.println(" SU MO TU WE TH FR SA");
		System.out.println("---------------------");

		int weekday = get_weekday(year, month, 1);

		for (int i = 0; i < weekday; i++) {
			System.out.print("   ");
		}
		int days = get_maxDayOfMonth(year, month);

		int count = 7 - weekday;
		int delim = count < 7 ? count : 0;

		for (int i = 1; i <= days; i++) {

			System.out.printf("%3d", i);

			if (i % 7 == delim) {
				System.out.println();
			}
		}
		System.out.printf("\n\n");
	}
	
	public int get_weekday(int year, int month, int day) {

		int standard_Year 			= 1970;
		final int STANDAD_WEEKDAY 	= 4;

		int count = 0;

		for (int y = standard_Year; y < year; y++) {
			
			int year_Delta = isLeapYear(y) ? 366 : 365;
			count += year_Delta;
		}

		for (int m = 1; m < month; m++) {
			
			int month_Delta = get_maxDayOfMonth(year, m);
			count += month_Delta;
		}
		
		count += day - 1;
		
		int weekday = (count + STANDAD_WEEKDAY) % 7;
		return weekday;
	}
}
년도를 입력하세요.(EXIT : -1)
YEAR> 2021
월을 입력하세요.
MONTH> 2

     -2021 2-
 SU MO TU WE TH FR SA
---------------------
     1  2  3  4  5  6
  7  8  9 10 11 12 13
 14 15 16 17 18 19 20
 21 22 23 24 25 26 27
 28

년도를 입력하세요.(EXIT : -1)
YEAR> 2020
월을 입력하세요.
MONTH> 2

     -2020 2-
 SU MO TU WE TH FR SA
---------------------
                    1
  2  3  4  5  6  7  8
  9 10 11 12 13 14 15
 16 17 18 19 20 21 22
 23 24 25 26 27 28 29


년도를 입력하세요.(EXIT : -1)
YEAR> -1
종료

▷ 기준 = 1970.01.01.목

일=0
월=1
화=2
수=3
목=4 → 기준! STANDAD_WEEKDAY

int standard_Year 			= 1970;
final int STANDAD_WEEKDAY 	= 4;

▷ 년

1970년도를 기준으로
1년 씩 365를 더하기
※ 윤년은 366을 더하기

ex)
1971년 = 365
1972년 = 365 + 365

for (int y = standard_Year; y < year; y++) {
  int year_Delta = isLeapYear(y) ? 366 : 365;
  count += year_Delta;
}

▷ 월

년도에 일수를 더함

ex)
1971년 2월 = 365 + 31(1월 것 까지)
1972년 2월 = 365 + 365 + 31(1월 것 까지)

for (int m = 1; m < month; m++) {

  int month_Delta = get_maxDayOfMonth(year, m);
  count += month_Delta;
}

▷ 일

day는 호출 받을 때 1로 받음
이걸 카운트에서 빼 줘야 함

//호출
int weekday = get_weekday(year, month, 1);

public int get_weekday(int year, int month, int day)

년, 월의 일수를 받았다면
기준요일인 목요일의 4만큼 띄어쓰기 해 준것도 카운트
다 카운트하고 7로 나눠 준 것의 나머지 값만큼
띄어쓰기 하면서 돌아가게 weekday로 넣어줌

count += day - 1;

  int weekday = (count + STANDAD_WEEKDAY) % 7;
  return weekday;