캘린더4

SUADI·2022년 4월 4일

오늘은 난이도가 매우 어려워서 강의 하나밖에 나가지 못했다. 며칠을 고민해서 겨우 원하는 결과를 얻어내기는 했지만 여전히 처음부터 다시 하려고 하면 못할 것 같다. 포스팅을 하면서 머릿속을 다시 한번 정리해 봐야겠다. 어쨋든 TIL 시작

1. 년, 월만 입력 받아서 정확한 달력 출력(요일까지 맞추기)

//Prompt

import java.util.Scanner;

public class Prompt {
	public void runPrompt() {
    	Scanner scanner = new Scanner(System.in);
        Calendar cal = new Calendar();
        
        while(true) {
        	System.out.println("년을 입력하세요.");
            int year = scanner.nextInt();
            if (year < 1) {
            	System.out.println("bye");
                break;
            }
            
            System.out.println("월을 입력하세요.");
            int month = scanner.nextInt();
			if (month < 1 || month > 12) {
            	System.out.println("잘못 입력하셨습니다.");
                continue;
            }
            
            cal.printCalendar(year, month);
        }
    }
    
    public static void main(String[] args) {
    	Prompt p = new Prompt();
        p.runPrompt();
    } 
}
// Calendar

public class Calendar {
	public static final int[] MAX_DAYS = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    public static final int[] LEAP_MAX_DAYS = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    public int maxDaysOfMonth(int year, int month) {
    	if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
        	return LEAP_MAX_DAYS[month];
        }
        
        else {
        	return MAX_DAYS[month];
        }
    }
    
    public void printCalendar(int year, int month) {
    	System.out.printf("\t\t<<%d년 %d월>>\n", year, month);
        System.out.println("\tSU\tMO\tTU\tWE\tTH\tFR\tSA");
        System.out.println("\t--------------------------");
        
        
        int maxDay = maxDaysOfMonth(year, month);
        int weekday = getWeekdays(year, month);
        
        for (int i=0; i<weekday; i++) {
        	System.out.print("\t");
        }
        
        for (int j=1; j<7-weekday; j++) {
        	System.out.printf("\t%d", j);
        }
        System.out.println();
        
        int cnt = 7 - weekday;
        if (cnt == 7) {
        	cnt = 0;
        }
        
        for (int k=8-weekday; k<maxDay; k++) {
        	System.out.printf("\t%d",k);
       		if (k % 7 == cnt) {
            	System.out.println();
            }       
        }
        System.out.println();
       	System.out.println();        
    }
	
    public int getWeekdays(int year, int month) {
        int initialDay = 1; // 1년 1월 1일이 월요일 기준 잡음

		// 년
        int yearSum = 0;
        for (int i=1; i<year; i++) {
        	for (int j=1; j<=12; j++) {
            	yearSum += maxDaysOfMonth(i,j);
            }
        }
        
        // 월
        int monthSum = 0;
        for (int k=1; k<month; k++) {
        	monthSum += maxDaysOfMonth(year, k);
        }
        
        return (initialDay + yearSum + monthSum) % 7;
    }
}

(1) getWeekday 함수

년, 월의 입력만 받아서 실제 달력을 출력 시키는데에 가장 중요한 논리는 특정일을 기준점으로 두고 그 기준일로부터 날짜를 더하고 빼서 내가 원하고자 하는 날의 달력을 출력해 내는 것이다. 더 쉽게 설명을 하자면, 1년 1월 1일을 월요일로 기준을 두자. 이렇게 기준점만 두더라도 알 수 있는 사실이 여러가지가 있다. 한 달이 31일인 경우, 31 % 7 = 3일이므로 다음달 1일은 저번달 1일의 요일로부터 3일후의 요일이 된다. 1월 1일이 월요일이므로 2월 1일은 목요일이 된다. 한 달이 30일이면 2일 뒤의 요일이고, 28일이면 전달 1일의 요일과 같다. 그리고 년으로 넘어가서 윤년을 고려해보면 올해가 평년이면 올해 1월 1일 요일의 다음 요일이 그 다음해의 요일이 된다. 1년 1월 1일이 월요일이면 2년 2월 1일은 화요일이 된다. 왜냐하면 365 % 7 = 1일이기 때문이다. 올해가 윤년이라면 366 % 7 = 2일이므로 다음해의 1월 1일은 다다음 요일이 된다. 이러한 것들을 일반화해서 논리적으로 풀면 1년 1월 1일을 기준으로 잡고 입력받은 년도만큼 날짜를 더해서 7로 나눈 나머지만큼 요일을 계산할 수 있고, 더 나아가서 월까지 더하면 매 달의 요일을 계산할 수 있다.

0개의 댓글