자바의 정석 10장 (26일차) - Calendar 클래스

728x90

Calendar 클래스 

추상클래스이므로 getInstance 메서드를 통해 구현된 객체를 얻어야 한다.

새롭게 new를 사욯해서 Calendar 자료형을 선언하는 것은 불가능

 

Calendar를 사용해서 날짜필드 가져오기

  • 아래 형식으로 가져온다.

출력값:

28
2022

		Calendar ca = Calendar.getInstance();
//		캘린더 추상클래스를 선언하면 시스템의 최신 시간을 가져온다
		int year = ca.get(Calendar.YEAR);
//		현재 시스템 시간 상의 최신 년도
		int lastday = ca.getActualMaximum(Calendar.DATE);
//		이달의 마지막 날
		System.out.println(lastday);
		System.out.println(year);

 

Calendar 시간 차이 구하기 예시

  • getTimeInMillis로 지난 시간을 1/1000으로 구한 후 초단위로 환산해서 일단위로 변환한다
  • 이 때 일단위는 (24시간*60분*60초)로 나눠서 환산한다
//		두 날짜간의 시간의 차이를 알려면 전부 초로 환산한 후에 일(24시간*60분*60초)로 나눈다
		military.set(2020,3,6);
		long differ =  (ca2.getTimeInMillis() - military.getTimeInMillis()) / 1000;
		System.out.println(differ/(24*60*60));
//		681일

 

  • 위의 예시를 좀더 심화하여 오늘 00시 기준으로 얼마나 시간이 지났는지를 표시하는 프로그램을 만들어보면 아래와 같이 나온다.
    1. 현재 시각을 Calendar 클래스로 받아오고 다른 Calendar 클래스에는 현재 시간을 0시 0분 0초로 맞춰놓는다.
    2. 현재시각 - 0시를 연산하여 1/1000으로 구한 후에 1000을 다시 곱해 총 몇초가 지났는지 체크한다
    3. 받아온 초를 거스름돈 구하는 알고리즘을 사용하여 시간, 분, 초로 다시 연산한 후 표시한다
      1. 거스름돈: 제일 큰 수로 나눈 후에 구하고 난 나머지 값을 그다음 작은 수로 나누면 다음 값이 나옴

출력문: 현재시각: 오전 6시 34분 32초

		Calendar ca = Calendar.getInstance();
		Calendar ca2 = Calendar.getInstance();

		ca.set(Calendar.HOUR_OF_DAY, 0);
		ca.set(Calendar.MINUTE, 0);
		ca.set(Calendar.SECOND, 0);
		
		long differ = Math.abs((ca2.getTimeInMillis() - ca.getTimeInMillis()) / 1000);
		timecounting(differ);
		
	}
	static void timecounting(long d) {
		int[] tmp = {3600,60,1};
		int[] time = new int[3];
		for(int i = 0; i<3; i++) {
			time[i] = (int)d/tmp[i];
			d%=tmp[i];
		}
		if(time[0]>12) {
			System.out.println("현재시각: 오후 " + (time[0]-12) + "시 " + time[1] + "분 " + time[2] + "초");
		}
		System.out.println("현재시각: 오전 " + time[0] + "시 " + time[1] + "분 " + time[2] + "초");

Calendar 메서드

1. clear()메서드를 사용하여 전체시간을 초기화 시킬 수 있다.

  • 아래처럼 clear를 공백으로 선언하면 전체시간을 초기화시켜 1970년으로 설정되고 따로 필드를 지정하여 특정 시간/날짜만 초기화 시킬 수 있다.

출력문:

초기화 전 시간: 54
초기화 후 시간: 0
Thu Jan 01 00:00:00 KST 1970

		System.out.println("초기화 전 시간: " + ca3.get(Calendar.MINUTE));
		ca3.clear(ca3.MINUTE);
		System.out.println("초기화 후 시간: " + ca3.get(Calendar.MINUTE));
		ca3.clear(); // 모든 시간 초기화
		System.out.println(new Date(ca3.getTimeInMillis()));

 

아래의 필드를 2. get 또는 set을 사용하여 읽어오거나 설정할 수 있다.

 

3. roll & add

add를 사용하면 다른 필드와 지정한 필드의 숫자를 동시에 변경한다.

  • roll을 사용하면 다른 필드에 영향을 미치지 않고 지정한 필드의 숫자만 변경한다.
  • 예를 들어 2022년 12월 31일로 설정해놓은 Calendar 클래스에 add 메서드로 월을 1일 추가하면 2023년 1월 31일로 변경되지만 roll을 사용할 경우 2022년 1월 31일로 월만 변경되고 년은 그대로 출력된다.
  • 아래의 예시 참조

*예시에서는 +만 사용했지만 -도 가능하다. 필드에 -만 붙여서 선언!

 

출력문: 

Sat Dec 31 14:29:57 KST 2022 - 원래의 설정값
Mon Jan 31 14:29:57 KST 2022 - roll을 사용하여 월만 변경한 값, 년도는 변경되지 않음
Tue Feb 01 14:29:57 KST 2022 - add를 사용하여 date를 변경한 값 (월 & 일이 동시에 변경!)

		Calendar ca3 = Calendar.getInstance();
		
		ca3.set(2022, 11, 31);
		System.out.println(new Date(ca3.getTimeInMillis()));
		ca3.roll(ca3.MONTH, 1);
		System.out.println(new Date(ca3.getTimeInMillis()));
		ca3.add(ca3.DATE, 1);
		System.out.println(new Date(ca3.getTimeInMillis()));

 

 

Calendar 메서드를 사용한 달력 출력

 

1. Run Configuratoin에서 출력할 문자열을 지정해 출력하였다. (예시는 2022년 2월을 예시로 두었다)

2. get(Calendar.DAY_OF_WEEK)으로 지정한 달의 시작 요일을 구하고

3. 다른 Calendar 클래스로 set()지정을 다음달, 날짜(date)에 -1을 하여 지정 달의 마지막 날을 구한다.

4. for문으로 시작 요일의 숫자만큼 공백을 달력에 출력하여 시작요일의 공백을 넣어주고

5. 다른 for문으로 시작요일의 숫자와 매개변수 i를 동시에 증가시켜 매번 시작요일이 7로 나누어 떨어질 때 마다 줄 띄어쓰기를 해준다.

 

출력문:

		Calendar start = Calendar.getInstance();
		Calendar end = Calendar.getInstance();
		int year = Integer.valueOf(args[0]);
		int month = Integer.valueOf(args[1]);
		
		start.set(year, month-1, 1);
		end.set(year, month, 1);
		end.add(Calendar.DATE, -1);
		
		int dayweek = start.get(Calendar.DAY_OF_WEEK);
//		지정된 요일 불러오기
//		일욜부터 1-7순 일월화수목금토
		
		System.out.println();
		System.out.printf("=========[%d월]=========\n", month);
		System.out.println(" SU MO TU WE TH FR SA ");
		
//		시작요일이 3, 즉 화요일이기 때문에 일, 월을 2번씩 빈칸으로 두고
//		다음 for문에서 달력을 프린트한다
		for(int i = 1; i<dayweek; i++) {
			System.out.print("   "); 
		}
		
		for(int i = 1, n = dayweek; i<=end.get(Calendar.DATE); i++, n++) {
			System.out.printf("%3d", i);
			if(n%7 == 0) {
				System.out.println();
			}
		}

 


Calendar 클래스를 Date 클래스로 변환

거의 deprecated 되었지만 아직까지 많이 쓰고있는 방식이기 때문에 외우지는 말고 눈에만 익도록 만들자.

*원래 Calendar 클래스의 출력문은 난해하나 출력문 메서드로 가독성을 높임

 

	public static void main(String[] args) {
		Calendar ca = Calendar.getInstance();
		Date d = new Date(ca.getTimeInMillis());
//		Calendar 클래스를 Date클래스로 변환
		System.out.println(d);
		
		ca.setTime(d);
//		Date클래스를 Calendar클래스로 변환
		time(ca);
	}

출력문:

Thu Feb 17 10:08:01 KST 2022
2022년 1월 17일

 

 

Calendar 클래스 Date 클래스를 활용한 응용 연습문제

 

문제:

어떤 회사의 월급날이 매월 21일이다. 두 날짜 사이에 월급날이 몇 번있는지 계산해서 반환하는 메서드를 작성하고 테스트 하시오.

 

출력문: 

2020-01-01 ~ 2020-01-01:월급 받은 수 0
2020-01-21 ~ 2020-01-21:월급 받은 수 1
2020-01-01 ~ 2020-03-01:월급 받은 수 2
2020-01-01 ~ 2020-03-23:월급 받은 수 3
2020-04-23 ~ 2020-01-21:월급 받은 수 0
2021-01-22 ~ 2020-03-21:월급 받은 수 0

		
		Calendar fromCal = Calendar.getInstance();
		Calendar toCal = Calendar.getInstance();
		fromCal.set(2020,0,1);
		toCal.set(2020,0,1);
		printResult(fromCal, toCal);
		System.out.println(paycheckCount(fromCal, toCal));
		
		fromCal.set(2020,0,21);
		toCal.set(2020,0,21);
		printResult(fromCal, toCal);
		System.out.println(paycheckCount(fromCal, toCal));
		
		fromCal.set(2020,0,1);
		toCal.set(2020,2,1);
		printResult(fromCal, toCal);
		System.out.println(paycheckCount(fromCal, toCal));
		
		fromCal.set(2020,0,1);
		toCal.set(2020,2,23);
		printResult(fromCal, toCal);
		System.out.println(paycheckCount(fromCal, toCal));
		
		fromCal.set(2020,3,23);
		toCal.set(2020,0,21);
		printResult(fromCal, toCal);
		System.out.println(paycheckCount(fromCal, toCal));
		
		fromCal.set(2021,0,22);
		toCal.set(2020,2,21);
		printResult(fromCal, toCal);
		System.out.println(paycheckCount(fromCal, toCal));
	
	}
	static void printResult(Calendar from, Calendar to) {
		Date fromDate = from.getTime();
//		Calendar 클래스를 getTime으로 Date클래스로 변환
		Date toDate = to.getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//		SimpleDateFormat으로 기본 형식을 지정해준 후 Date 클래스를 출력한다
		System.out.print(sdf.format(fromDate)+" ~ "
				+sdf.format(toDate)+":");
		}
		
	static int paycheckCount(Calendar from, Calendar to) {
		int count = to.get(Calendar.MONTH) - from.get(Calendar.MONTH);
//		월급을 받은 수를 count로 지정한다. 월이 다른만큼 count의 기본 개수를 지정했다.
		if(from.get(Calendar.DAY_OF_MONTH)<=21){
			count++;
//			만약 시작일이 21일 이전이면 count에 1을 추가한다.
			if(to.get(Calendar.DAY_OF_MONTH)<21)
				count--;
//			마지막날이 21일 이하이면 중복중첩을 막기위해 1을 제거한다.
		}
		if(to.get(Calendar.YEAR) - from.get(Calendar.YEAR) < 0 || to.get(Calendar.MONTH) - from.get(Calendar.MONTH) < 0){
			return 0;
//			만약 년도의 차이가 -거나 월의 차이가 -라면 0을 반환한다.
		}
		return count;
	}
}
728x90