오늘은 어디로 갈까...

날짜(Date) 0x00 본문

낙서

날짜(Date) 0x00

剛宇 2009. 2. 26. 20:45
자바에서 날짜와 시간을 표현하는데에 java.util.Date를 클래스를 많이 쓴다.
그리고 java.text.SimpleDateFormat 클래스를 이용해서 원하는 형식으로 출력할 수 있다.

		Date date = new Date();
		System.out.println(date);
		
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		System.out.println(format.format(date));


new Date()를 사용하면 현재 시간으로 생성이된다. 원하는 날짜 시간으로 만들려면 어떻게 해야할까?
Date 생성자를 보면 날짜를 입력하는게 있지만, Deprecated 생성자이다. 사용하지 말자.
    @Deprecated
    public Date(int year, int month, int date, int hrs, int min, int sec) {
	int y = year + 1900;
	...  생략 ...
    }


그럼 어떻게 해야할까? API 문서를 보면, long값을 입력받는 생성자가 있다.
이 생성자는 1970년 1월 1일 00시 00분 00초부터 경과한 시간을 밀리초(milliseconds) 단위로 넣어주면 되는것이다.
    public Date(long date) {
        fastTime = date;
    }


근데 왜 1970년 1월 1일 일까...? 1970년대 유닉스 표준을 만들때 1970년 1월 1일 자정부터 경과한 시간을 초(second)로 나타낸다고 정의했기 때문이다.
그리고 자료형으로는 32비트 signed형을 사용했다.  당시는 컴퓨터 자원(메모리등)가 아주 작았기 때문에 최소한의 비용으로 최대의 효과를 볼려고 이런 잔머리를 굴린것이다.
이렇게하므로서 32비트를 가지고 1901-12-14 05:15:52부터 2038-01-19 12:14:07까지 표현할 수 있으니 얼마나 대단한가.
단, 32비트 signed형으로는 2038년 이후는... 안드로메다로 가버릴 수도..)
32비터 singed형하면 자바의 int가 떠오른다. 한번 출력해볼까?
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		System.out.println(format.format(new Date(Integer.MIN_VALUE * 1000l)));
		System.out.println(format.format(new Date(Integer.MAX_VALUE * 1000l)));

* 출력결과
1901-12-14 05:15:52.000
2038-01-19 12:14:07.000

자, 원래의 문제로 돌아와서, 그럼 어떻게 저 long값을 계산할 수 있을까?
다행히도 java.util.Calendar 클래스를 이용하면 쉽게 만들 수 있다.
Calendar를 생성한 다음, getTimeInMillis() 메소드를 호출하면 된다.
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		Calendar cal = Calendar.getInstance();
		System.out.println(format.format(new Date(cal.getTimeInMillis())));
		System.out.println(format.format(cal.getTime()));
* 출력결과
2009-02-25 20:38:59.937
2009-02-25 20:38:59.937

* 참고 : getTime() 메소드는 new Date(getTimeInMillis())를 리턴해준다.

그럼, 1978년 6월 15일이란 날짜를 만들어보자.
		Calendar cal = Calendar.getInstance();

		int year = 1978;
		int month = 6;
		int date = 15;
		int hourOfDay = 0;
		int minute = 0;
		int second = 0;
		cal.set(year, month - 1, date, hourOfDay, minute, second);
		System.out.println(format.format(cal.getTime()));
* 출력 결과
1978-06-15 00:00:00.500
여기서 주의할 것은 j월(month)은 1을 빼줘야한다. 내부적으로 0부터 시작함으로 1월달은 0의 값을 들어가야한다.
set(int, int, int, int, int, int) 메소드를 살펴보면 아래와 같다.
   public final void set(int year, int month, int date, int hourOfDay, int minute,
                          int second)
    {
        set(YEAR, year);
        set(MONTH, month);
        set(DATE, date);
        set(HOUR_OF_DAY, hourOfDay);
        set(MINUTE, minute);
        set(SECOND, second);
    }

년도는 그대로 유지하고 월(month)와 일(date)만 7월 19일로 변경해보자.
		Calendar cal = Calendar.getInstance();

		int year = 1978;
		int month = 6;
		int date = 15;
		int hourOfDay = 0;
		int minute = 0;
		int second = 0;
		cal.set(year, month - 1, date, hourOfDay, minute, second);
		System.out.println(format.format(cal.getTime()));

		// 월일 변경
		cal.set(Calendar.MONTH, 7 - 1);
		cal.set(Calendar.DATE, 19);
		System.out.println(format.format(cal.getTime()));
* 출력 결과
1978-06-15 00:00:00.500
1978-07-19 00:00:00.500

현재 필자의 경우는 밀리초 값이 500이라서 왠지 보기가 안좋다.(결벽증인가) 그래서 clear() 메소드를 사용해서 초기화 한 후 사용하던지 아니면 밀리초(Calendar.MILLISECOND)까지 값을 지정해주면 보다 깔끔한 날짜를 볼 수 있다.
		Calendar cal = Calendar.getInstance();
		cal.clear();
		System.out.println(format.format(cal.getTime()));

* 출력 결과
1970-01-01 00:00:00.000

1978년 7월 19일은 무슨 요일일까? 한번 만들어보자
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(1978, 7 - 1, 19);
		System.out.println(format.format(cal.getTime()));
		System.out.println(cal.get(Calendar.DAY_OF_WEEK));

출력결과
1978-07-19 00:00:00.000
4

get(int) 메소드를 이용해서 가져올 수 있다. 요일이니 Calendar.DAY_OF_WEEK를 사용하면 된다.
결과는 숫자로 반환되는데, 일요일(1), 월요일(2), 화요일(3)... 으로 된다.(API에 나왔있음)
출력값이 4이니 수요일이 되겠다.
자. 그럼 1978년 7월 19일로부터 100일째 되는 날은 언제일까?
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(1978, 7 - 1, 19);
		System.out.println(format.format(cal.getTime()));
		cal.add(Calendar.DATE, 100);
		System.out.println(format.format(cal.getTime()));

* 출력 결과
1978-07-19 00:00:00.000
1978-10-27 00:00:00.000

이 add(int, int) 메소드를 이용해서 년/월/일/시/분/초/밀리초를 마음대로 늘렸다 줄였다 할 수 있는것이다.
이 메소드와 비슷한 roll(int, int)이란게 있는데, 이놈은 해당 단위만 증/감을 한다는게 차이다.
즉 100일을 추가면 월(month)이 초과해서 증가해야하는데, 이놈은 일(date)을 추가하면 일(date)만 변할뿐이지,
월(month), 년(year)같은거에는 영향을 안미친다는 소리이다. 한번 테스트해볼까.
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(1978, 7 - 1, 19);
		System.out.println(format.format(cal.getTime()));
		cal.roll(Calendar.DATE, 100);
		System.out.println(format.format(cal.getTime()));

* 출력 결과
1978-07-19 00:00:00.000
1978-07-26 00:00:00.000
설명대로 일(date)만 변한것을 알 수 있다.


자, 마지막으로 1978년 7월달이 몇일까지 있는지와 1978년의 총일수를 구해보도록하자.
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(1978, 7 - 1, 19);
		System.out.println(format.format(cal.getTime()));
		System.out.println(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
		System.out.println(cal.getActualMaximum(Calendar.DAY_OF_YEAR));

* 출력 결과
31
365

마지막이라고 했지만, 재미있는것 하나만 더 보여주겠다.
2009년 2월은 28일까지 있다. 그래서 2009년 2월 1일로 날짜를 설정하고 getActualMaximum(int)을 호출하면 당연히 28이란 값이 반환된다. 그런데, 날짜를 2009년 2월 30일로 설정하면 getActualMaximum(int)로 호출하면 어떻게 될까? 결과부터 말하자면,  set(int, int)메소드가 워낙 똑똑해서 2009년 2월 30일로 설정하면 알아서 2009년 3월 2일로 변환해준다. 이 상태에서 getActualMaximum(int) 메소드가 호출이되니, 3월달의 일(date)수 즉 31이란 값이 나오게된다. 간혹 어의없는 실수를 하게되니 주의하도록하자.
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(2009, 2 - 1, 1);
		System.out.println(format.format(cal.getTime()));
		System.out.println(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
		
		cal.set(2009, 2 - 1, 30); // 2009년 2월 30일로 설정
		System.out.println(format.format(cal.getTime()));
		System.out.println(cal.getActualMaximum(Calendar.DAY_OF_MONTH));

* 출력 결과
2009-02-01 00:00:00.000
28
2009-03-02 00:00:00.000
31