자바의 GregorianCalendar를 이용하여 date를 계산하는 과정에서 문제가 발생해서 한 동안 애를 먹었다. 평소에 그냥 아무 문제 없이 돌아가던 테스트가 갑자기 에러를 발생시킨 것이다. 문제는 그 이후에 다시 그 문제가 발생하지 않았는데, 그냥 그러려니 하고 넘어가기에는 이해가 안가는 부분이 있어서 에러를 발생시킨 원인에 대해 알아봤다.
문제의 에러는 GregorianCalendar에 현재 timestamp를 저장해 놓고 add() method를 이용해서 13일씩 빼 나가던 중 발생했다. 테스트 시점의 timestemp는 2008-03-18 00:39:51이었고, 다음의 code를 실행시켰다. (그 후에는 아무리 같은 테스트를 수행해도 한 시간이 더해지는 경우는 생기지 않았다. ㅡ.ㅡ;;)
GregorianCalendar cal = new GregorianCalendar();
GregorianCalendar cal1 = (GregorianCalendar) cal.clone();
cal.setTime(new java.util.Date()); // 2008-03-18 00:39:51 이 저장되었다.
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int step = 13;
for (int i = 0; i < 8000; i += step)
{
cal1.setTime(cal.getTime());
cal1.add(Calendar.DAY_OF_YEAR, -i);
System.out.println(df.format(cal1.getTime()));
}
척 보기에도 아주 간단한 코드인데, 문제는 아래와 같이 결과가 나오던 중 1988-05-08 01:39:51이라는 엉뚱한 값이 나와버린 것이다. 도대체 저 한시간이 어디서 더해진거란 말인가? ㅡ.ㅡ;;
2008-03-18 00:39:51
2008-03-05 00:39:51
2008-02-21 00:39:51
2008-02-08 00:39:51
...
1988-06-03 00:39:51
1988-05-21 00:39:51
1988-05-08 01:39:51 <- 여기가 문제의 값이 출력된 부분이다.
1988-04-25 00:39:51
1988-04-12 00:39:51
...
도전 정신이 생기면 아래 more를 누르지말고 스스로 그 원인을 찾아보길~
more..
솔직히 귀찮아서 그냥 레포팅한 영어 원문으로...
Please refer the SUN’s bug database: http://bugs.sun.com/bugdatabase/view_bu ··· D4958050
In that bug report, you can find below explanation:
In general, it's impossible for the time fields (HOUR_OF_DAY, MINUTE, etc) to be equal to their prior values because of time zone offset changes (raw offset and/or daylight time).
For example, if the date/time is 2003-4-5 (Sat) 2:30:00 local time in the America/Los_Angeles time zone, adding one day would create 2003-4-6 (Sun) 2:30 which doesn't exist due to the daylight saving time.
Then, GregorianCalendar adjusts the time to 1:30.
To help your understanding, refer LA’s daylight saving time start/end dates between year 2000 and 2009: http://www.timeanddate.com/worldclock/t ··· Fn%3D137
In that document, you can find that 2003-4-6 (Sun) 2:30 does not exist because after 2003-4-6 (Sun) 1:59:59, the daylight saving time started and 2003-4-6 (Sun) 2:00:00 was changed to 2003-4-6 (Sun) 3:00:00.
In Korea, we do not use DST, however, in 1987 and 1988, we used DST just for the Seoul Olympics.
And you can find the Seoul’s daylight saving time start/end dates here: http://www.timeanddate.com/worldclock/t ··· r%3D1980
You can find that 1988-5-8 00:39:51 does not exist because of the same reason.
There were several time zone changes in Korea such as from UTC offset +8:30 hours to UTC offset +9:30 hours in KST at 1904-12-1 00:00:00 (à 1904-12-1 00:30:00).
In that cases next result can be obtained from GregorianCalendar’s add() method.
before sub: 1904-12-2 0:10:0+540
after sub: 1904-12-1 0:40:0+540 (cal.add(cal.DAY_OF_YEAR, -1))
You can also find those time zone changes in http://www.timeanddate.com/worldclock
Trackback Address >> http://oosoom.org/trackback/97
댓글을 달아 주세요
ㅋ, 그런 경우가. 그래서 locale, calendar, keyboard 등이 한 데 얽혀 있는거군. 엄청 황당 했었겠군. 난 예전에 2 + 2가 4로 안나와서 거 때문에 당황한 적이 있었던 거 같다. 왜 그랬는 지는 지금은 기억이 안나네.
그래서 GregorianCalendar를 쓸 때는 아주 조심해야 할 것같다. DST가 적용되는 지역에서 쓸 때는 특히나 더.
2+2가 4가 안되는 경우를 빨리 찾아서 올려라~
GregorianCalendar를 time zone과 상관 없이 단순히 날짜 계산을 위해 사용하고 싶다면 GregorianCalendar를 생성할 때 GMT로 time zone을 세팅하면 될 것같다.
즉 다음과 같이 한다는 말~
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));