java 달력 - 윤년구하기!

윤년구하기

솔직히 요즘 언어에서 Date관련 데이터 구조가 없는경우가 거의 없다!

LocalDate now = LocalDate.now();
now.isLeapYear(); //객체의 년도가 윤년인지 true false반환

하지만 그렇지 않은 언어도 분명 있을터! 윤년을 구하는 공식을 간단하게 java코드로 만들어보자.

다른 언어에서도 마찬가지로 적용 가능할 것이다.

특이한 2월….

솔직히 2월달 마지막날짜만 아니면 윤년 구할 필요도 없다….

하지만 지구인으로써 윤년은 꼭 필요한 정보이다…. 윤년을 알수있는 공식은 다음과 같다.(feat 그레고리력)

  • 서력 기원 연수가 4로 나누어떨어지는 해는 윤년으로 한다.

  • 서력 기원 연수가 4, 100으로 나누어떨어지는 해는 평년으로 한다.

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

즉 년도가 4로 나누어 떨어지면서 100으로 나뉘지 않으면서 그중에 400으로 나뉘어지면 윤년으로 본다!

public static int getLastDay(int year, int month) {
  int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  return isleapyear(year) && month==2 ? 29 : days[month-1];
}

public static boolean isleapyear(int year) {
  return year%100!=0 && year%4==0 || year%400==0 ? true : false;
}

윤년은 구하는 이유가 무엇인가?
바로 달력을 그리기 위해서지!

달력을 java로 그려보자….

달력을 그리려면
달의 1일이 몇일이지, 마지막일이 몇일인지 알아야한다.

아래 메서드로 시작요일와 마지막일을 구하는데 마지막일은 윤년만 구할수 있다면 구할수 있는 것 이고

시작요일이 까다롭다…

시작요일을 구하는 공식은 1년 1월 1일이 월요일임으로
원하는 날짜까지의 일 수 를 구한후 7로 나눈 나머지값이 요일이 된다.

그럼 2019-4-1일의 요일을 구하고 싶다면 1-1-1부터 2019-4-1까지의 일 수 를 구하면 된다.

public static int getDayOfWeek(int year, int month) {
  int totDays = (year-1)*365 + (year-1)/4 - (year-1)/100 + (year-1)/400;
  for (int i = 1; i < month; i++) 
  {
    totDays+=getLastDay(year, i);
  }
  totDays+=1;

  return totDays%7;
}

일단 1년 ~ 2018년 까지의 일수를 구한다.

365 곱한것 뒤의 + (year-1)/4 - (year-1)/100 + (year-1)/400는 윤년에 해당하는 일수를 추가로 더해주기 위한것,
윤년의 경우 366일이니까!

그리고 4월 1일의 요일을 구해야 하니 1월 ~ 3월 까지의 일수를 for문을 통해 추가로 더해준다.

month4가 들어가면 1, 2, 3이 getLastDay메서드의 매개변수로 들어가게 된다.

getLastDay는 다음과 같다.

public static int getLastDay(int year, int month) {
  int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  return isleapyear(year) && month==2 ? 29 : days[month-1];
}

미리 마지막일을 저장해 놓은 배열을 정의해두었다. (2월은 윤년의 경우 29일로 반환)

이제 달력 그리기를 위한 모든 값이 구해졌으니 달력을 그려보자!

public class Calender {
	public static void main(String[] args) throws IOException
	{
		int year, month;
		System.out.print("년 월 입력하세요: "); //2010 5
		Scanner sc = new Scanner(System.in);
		year = sc.nextInt();
		month = sc.nextInt();
		createCalendar(year, month);
	}
	
	public static void createCalendar(int year, int month)
	{
    //시작 요일과 마지막 날짜를 구하는 메서드
		int dayOfWeek = getDayOfWeek(year, month);
		int lastDay = getLastDay(year, month);
		printCalender(year, month, dayOfWeek, lastDay);
	}
	public static void drawLine(int n) //단순 선 긋는 함수
	{
		for (int i = 0; i < n; i++) 
      System.out.print('-');
		System.out.println();
	}
	
	public static void printCalender(int year, int month, int dayOfWeek, int lastDay) {
		System.out.printf("\t\t%d년 %d월\n",year,month);
		String week = "일월화수목금토";
		drawLine(50);
		for (int i = 0; i < 7; i++)
			System.out.printf("%c \t", week.charAt(i));
		System.out.println();
		drawLine(50);
    drawLine(50);
    
		int cnt=0;
		for (int i = 0; i < dayOfWeek; i++)
		{
			System.out.print('\t');
			cnt++;
    } //시작 요일 수만큼 공백을 준다.  
    
		for (int d = 1; d <= lastDay; d++)
		{
			System.out.printf("%d \t", d);
			if(cnt%7==6)
				System.out.println();
			cnt++;
		} //차례대로 요일 출력 1~30
 }

	public static int getDayOfWeek(int year, int month) {
		int totDays = (year-1)*365 + (year-1)/4 - (year-1)/100 + (year-1)/400;
		for (int i = 1; i < month; i++) 
		{
			totDays+=getLastDay(year, i);
		}
		totDays+=1;

		return totDays%7;
	}
	
	public static int getLastDay(int year, int month) {
		int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		return isleapyear(year) && month==2 ? 29 : days[month-1];
	}

	public static boolean isleapyear(int year) {
		return year%100!=0 && year%4==0 || year%400==0 ? true : false;
	}
}

출력

년 월 입력하세요: 2019 4
		2019년 4월
--------------------------------------------------
일 	월 	화 	수 	목 	금 	토 	
--------------------------------------------------
--------------------------------------------------
	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 	

모든 2019년에 해당하는 달력을 출력해보자(1~12 모두 출력)

그냥 출력하면 재미 없으니 3차원 배열을 사용해 출력해보자.

image02

달력 형식을 보면 총 6행 7열까지 나올 수 있다.
위 사진의 경우 5행 7열이지만 1일이 일요일부터 시작한다던가 하는 경우 6줄이 출력될 수 있다.

그럼으로 int형 배열 [6][7]짜리 2차원 배열을 사용해야 1달을 출력할 수 있다.

12달을 출력하려면 [12][6][7] 3차월 배열이 필요

package days13;

import java.util.Scanner;

public class Calender {
	public static void main(String[] args) {
		//달력 출력시 필요한것, 마지막 날짜, 시작 요일
		Scanner sc = new Scanner(System.in);
		int year = sc.nextInt();
		int[][][] dal = new int[12][6][7];
		createDaliek(dal, year);
		printDaliek(dal, year, 4); //4행으로 출력
	}

	private static void createDaliek(int[][][] dal, int year) {
		int[] lastDays = new int[12];
		int[] dayOfWeek = new int [12];
    int day = 1;
    //먼저 매 달의 시작요일, 마지막일을 저장할 배열을 초기화
		for (int i = 0; i < lastDays.length; i++) {
			lastDays[i] = getLastDay(year, i);
			dayOfWeek[i] = getDayOfWeek(year, i);
    }
    
		for (int i = 0; i < dal.length; i++) 
		{ //12개월
			day = 1;
			for (int j = 0; j < dal[0].length; j++)
			{ //6반복
				for (int k = 0; k < dal[0][0].length; k++) 
        { //7반복
          // 시작요일이 배열 인덱스 j*7+k보다 크다면 -1로 설정
          // day가 마지막일보다 커진다면 -1로 설정, -1은 출력되지 않는다.
					if(j*7+k < dayOfWeek[i] || day > lastDays[i])
						dal[i][j][k] = -1;
					else
						dal[i][j][k] = day++;
				}
			}
		} //end first for
	}
	private static void printDaliek(int[][][] dal, int year, int num)
	{			
		String week = "일월화수목금토";
		for (int z = 0; z < 12/num; z++)
		{
			for (int i = 0; i < num; i++) {
				System.out.printf("\t%d년 %d월\t\t", year, z*num+i+1 );
			}
      System.out.println();
      
			for (int i = 0; i < num; i++) {
				drawLine(27);
			}
      System.out.println();
      
			for (int i = 0; i < num; i++) {
				for (int p = 0; p < week.length(); p++) {
					System.out.printf("%c  ", week.charAt(p));
				}
				System.out.print("\t");
			}
      System.out.println();
      
			for (int j = 0; j < 2; j++) {
				for (int i = 0; i < num; i++) {
					drawLine(27);
				}
				System.out.println();
			}

      //눈을 크게 뜨고 확인하자....
			for (int i = 0; i < dal[0].length; i++)
			{
				for (int j = num*z; j < num+num*z; j++) 
				{
					for (int k = 0; k < dal[0][0].length; k++) {
						if(dal[j][i][k] == -1)
							System.out.print("    ");
						else
							System.out.printf("%2d  ", dal[j][i][k]);
					}
					System.out.print("\t");
				}
				System.out.println();
			}
			System.out.println();
		}
	}

	public static void drawLine(int n)
	{ 
		for (int i = 0; i < n; i++) 
			System.out.print('-');
		System.out.print("\t");
	}

	public static int getDayOfWeek(int year, int month) {
		int totDays = (year-1)*365 + (year-1)/4 - (year-1)/100 + (year-1)/400;
		for (int i = 0; i < month; i++) //0~11
			totDays+=getLastDay(year, i);
		totDays+=1;
		return totDays%7;
	}

	public static int getLastDay(int year, int month) {
		int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		return isleapyear(year) && month==1 ? 29 : days[month]; //0 = 1월, 11=12월
	}

	public static boolean isleapyear(int year) {
		return year%100!=0 && year%4==0 || year%400==0 ? true : false;
	}
}

일단 3차원 배열로 저장해 놓았다면 출력에서 for문막 약간 변경시켜주면 된다.

출력

2019
	2019년 1월			2019년 2월			2019년 3월			2019년 4월		
---------------------------	---------------------------	---------------------------	---------------------------	
일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	
---------------------------	---------------------------	---------------------------	---------------------------	
---------------------------	---------------------------	---------------------------	---------------------------	
         1   2   3   4   5  	                     1   2  	                     1   2  	     1   2   3   4   5   6  	
 6   7   8   9  10  11  12  	 3   4   5   6   7   8   9  	 3   4   5   6   7   8   9  	 7   8   9  10  11  12  13  	
13  14  15  16  17  18  19  	10  11  12  13  14  15  16  	10  11  12  13  14  15  16  	14  15  16  17  18  19  20  	
20  21  22  23  24  25  26  	17  18  19  20  21  22  23  	17  18  19  20  21  22  23  	21  22  23  24  25  26  27  	
27  28  29  30  31          	24  25  26  27  28          	24  25  26  27  28  29  30  	28  29  30                  	
                            	                            	31                          	                            	

	2019년 5월			2019년 6월			2019년 7월			2019년 8월		
---------------------------	---------------------------	---------------------------	---------------------------	
일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	
---------------------------	---------------------------	---------------------------	---------------------------	
---------------------------	---------------------------	---------------------------	---------------------------	
             1   2   3   4  	                         1  	     1   2   3   4   5   6  	                 1   2   3  	
 5   6   7   8   9  10  11  	 2   3   4   5   6   7   8  	 7   8   9  10  11  12  13  	 4   5   6   7   8   9  10  	
12  13  14  15  16  17  18  	 9  10  11  12  13  14  15  	14  15  16  17  18  19  20  	11  12  13  14  15  16  17  	
19  20  21  22  23  24  25  	16  17  18  19  20  21  22  	21  22  23  24  25  26  27  	18  19  20  21  22  23  24  	
26  27  28  29  30  31      	23  24  25  26  27  28  29  	28  29  30  31              	25  26  27  28  29  30  31  	
                            	30                          	                            	                            	

	2019년 9월			2019년 10월			2019년 11월			2019년 12월		
---------------------------	---------------------------	---------------------------	---------------------------	
일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	일  월  화  수  목  금  토  	
---------------------------	---------------------------	---------------------------	---------------------------	
---------------------------	---------------------------	---------------------------	---------------------------	
 1   2   3   4   5   6   7  	         1   2   3   4   5  	                     1   2  	 1   2   3   4   5   6   7  	
 8   9  10  11  12  13  14  	 6   7   8   9  10  11  12  	 3   4   5   6   7   8   9  	 8   9  10  11  12  13  14  	
15  16  17  18  19  20  21  	13  14  15  16  17  18  19  	10  11  12  13  14  15  16  	15  16  17  18  19  20  21  	
22  23  24  25  26  27  28  	20  21  22  23  24  25  26  	17  18  19  20  21  22  23  	22  23  24  25  26  27  28  	
29  30                      	27  28  29  30  31          	24  25  26  27  28  29  30  	29  30  31                  	

어디서 출력되냐에 따라 조금씩 깨지긴 하는데 이클립스 콘솔창에선 잘 출력된다.

끝!

카테고리:

업데이트: