자바 Calendar 클래스 set()방법의 함정 해결
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class TestCalendar {
public static void main(String[] args) {
String s = new SimpleDateFormat("yyyy-MM-dd")
.format(getLastDay(2017, 9));
System.out.println(s);
}
public static Date getLastDay(int year, int month) {
// Calendar
Calendar c = Calendar.getInstance();
//
c.set(Calendar.YEAR, year);
// , 0 , month - 1
c.set(Calendar.MONTH, month - 1);
// ,
int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
// Calendar
c.set(Calendar.DAY_OF_MONTH, lastDay);
return c.getTime();
}
}
처음 이 방법 을 사 용 했 을 때 는 정상 이 었 다.그 후에 10 월 31 일(이 날 짜 는 매우 중요 하 다)당일 에 테스트 할 때 전달 한 매개 변 수 는 2017 년 9 월,즉 위의 코드 였 으 나 결과 에 문제 가 생 겼 다.결 과 는 다음 과 같다.원래 2017-09-30 이 어야 하 는데 결 과 는 2017-10-01 입 니 다.제 가 테스트 를 해 봤 는데 이 방법 은 문제 가 없 었 는데 이런 문제 가 생 겼 습 니 다.나중에 제 가 단점 테스트 를 했 습 니 다.Calendar 인 스 턴 스 를 처음 가 져 왔 을 때 인 스 턴 스 의 필드 값 은 다음 그림 과 같 습 니 다.
근 데 집행 이 끝나 고 있 더 라 고요.
c.set(Calendar.MONTH, month - 1);
이 줄 의 코드 를 사용 할 때 Calendar 의 인 스 턴 스 에서 MONTH 필드 의 값 은 제 가 예상 한 8(월 필드 는 0 부터)이 아니 라 9 이 고 DAY 입 니 다.OF_MONTH 필드 의 값 은 31 에서 1 로 바 뀌 었 습 니 다.다음 그림 과 같 습 니 다.따라서 Calendar 인 스 턴 스 가 가 져 왔 을 때 는 10 월 31 일,인 스 턴 스 의 DAY 로 판단 할 수 있 습 니 다.OF_MONTH 의 값 은 31 입 니 다.MONTH 필드 의 값 을 8 로 설정 하면 9 월 에 30 일 밖 에 안 되 기 때문에 그 DAYOF_MONTH 값 만 1 이 많 으 면 자동 으로 1 일 뒤로 순연 되 며 2017-10-01 이 된다.
하지만 다음 에 도 실 행 됐 기 때문에 다른 문제 가 있 습 니 다.
c.set(Calendar.DAY_OF_MONTH, lastDay);
이 코드 는 마지막 날 짜 는 2017-10-31 이 어야 하 는데 run 의 결 과 는 2017-10-01 이 고 debug 의 결 과 는 2017-10-31 입 니 다.저 는 Calendar 류 에 스 레 드 안전 문제 가 존재 하 는 지 처음 느 꼈 습 니 다.그러나 나중에 생각 하 니 틀 렸 습 니 다.왜냐하면 저 는 메 인 스 레 드 에서 만 운행 하고 다 중 스 레 드 가 없 기 때문에 이 문제 가 존재 하지 않 습 니 다.
다음 날 에 저 는 문제 의 원인 을 발 견 했 습 니 다.위의 마지막 그림 에서 보 듯 이 debug 과정 에서 저 는 IDEA 의 watches 기능 으로 Calendar 인 스 턴 스 의 필드 값 을 살 펴 보고 get()방법 을 사 용 했 습 니 다.만약 에 제 가 이 몇 개의 get 방법 을 삭제 한 후에 run 과 debug 의 값 이 똑 같은 것 을 발 견 했 습 니 다.모두 2017-10-01 입 니 다.문 제 는 get()방법 에 있다 는 것 을 설명 합 니 다.
따라서 다음 과 같이 수정 할 수 있다.
코드 에서 변수 c 의 값 을 직접 인쇄 하면 get()방법 을 호출 하기 전에 변수 c 의 각 필드 값 은 set()방법 으로 설정 되 었 으 나 이 를 검증 하고 계산 하지 않 았 습 니 다.get()방법 을 호출 하 는 과정 에서 각 필드 를 검증 하고 계산 합 니 다.일부 소스 코드 를 살 펴 보 았 습 니 다.get(),add(),getTime()등 방법 을 호출 하 는 과정 에서 바 텀 은 coptute Time()방법 을 호출 하여 각 필드 의 시간 검증 계산 을 합 니 다.
또한 demo 테스트 를 실시 하여 위의 결론 을 입증 했다.다음 과 같다.
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class TestCalendar2 {
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, 8); // 9
c.set(Calendar.DAY_OF_MONTH, 32); // 32
System.out.println(c); // Calendar , getTime()
c.get(Calendar.MONTH);
System.out.println(c);
}
}
결 과 는 다음 과 같다.설 치 된 DAY 도OF_MONTH 값 은 명백히 불법 이지 만 get()방법 을 호출 하기 전에 진 위 를 계산 하 지 는 않 습 니 다.
문 제 를 조회 하 는 과정 에서 다른 문제 도 보 았 습 니 다.다음은 add(),set(),roll()방법의 차이 에 대해 설명 하 였 습 니 다.
예제 코드:
Calendar c = Calendar.getInstance();
c.set(2014, Calendar.MARCH, 31);
c.add(Calendar.MONTH, 13);
System.out.println(c.getTime());// 2015-04-30
c.set(2014, Calendar.MARCH, 31);
c.set(Calendar.MONTH, c.get(Calendar.MONTH) + 13);
System.out.println(c.getTime());// 2015-05-01
c.set(2014, Calendar.MARCH, 31);
c.roll(Calendar.MONTH, 13);
System.out.println(c.getTime());//2014-04-30
ADD 방법조 정 된 단 위 를 기점 으로(본 사례 에서 월)비교적 큰 단위(년)에 차임,진위 가 발생 한다.작은 단 위 는 작은 것 으로 조정 할 것 이다.
이 사례 에서 2014-03-31 에 13 개 월 을 더 하면 연도 회 진 위 는 2015 년 이다.4 월 31 일 은 존재 하지 않 기 때문에 4 월 30 일 로 조정 했다.
비교적 전형 적 인 운용 장면 은 달력 의 매달 전환 이다.
현재 날 짜 는 2014-03-31 입 니 다.[다음 달]버튼 을 클릭 하면 날 짜 는 2014-04-30 이 됩 니 다.
SET 방법
모든 부서 가 크게 조 정 될 것 이다.
이 사례 에서 2014-03-31 에 13 개 월 을 더 하면 연도 회 진 위 는 2015 년 이다.4 월 31 일 은 존재 하지 않 기 때문에 5 월 1 일 로 대폭 조정 하 였 다.
롤 방법
조 정 된 단 위 를 기점 으로(본 사례 에서 월)비교적 큰 단위(년)는 변 하지 않 을 것 이다.작은 단 위 는 작은 것 으로 조정 할 것 이다.
이 사례 에서 2014-03-31 에 13 개 월 을 더 하면 연 도 는 여전히 2014 년 이다.4 월 31 일 은 존재 하지 않 기 때문에 4 월 30 일 로 조정 했다.
일 은 년,월 에 따라 일의 수치 범 위 를 판단 한 후 1~31 사이 에 무한 순환 으로 굴 러 가지 만 연,월 의 수치 에 영향 을 주지 않 는 다.
총 결 세 가지:
1.add()는 두 가지 규칙 이 있 습 니 다.
a)수 정 된 필드 가 값 의 범 위 를 초과 하면 그 필드 보다 큰 필드 가 자동 으로 수 정 됩 니 다.
b)작은 필드 보다 가 변 적 이지 않 거나 값 범위 내 에 있 지 않 으 면(Calendar 의 구현 클래스 에 의 해 결 정 됩 니 다)이 작은 필드 는 가장 작은 값 으로 변 경 됩 니 다.
2.Roll()의 규칙 은 두 번 째 조항 밖 에 없다.
수 정 된 필드 가 값 의 범 위 를 초과 할 때,그 필드 보다 큰 필드 는 수정 되 지 않 습 니 다.그것 보다 작은 필드 는 가장 작은 값 으로 변 경 됩 니 다.
3、Set()
수 정 된 필드 보다 큰 필드 는 필드 가 커지 는 지,줄 어드 는 지 에 따라 자동 으로 크기 를 바 꿉 니 다.수 정 된 필드 보다 작은 필드 는 가 변 적 이지 않 거나 수치 범위 에 있 지 않 으 면 가장 작은 값 으로 자동 으로 커 집 니 다.
최초의 문제 로 돌아 가 지정 한 연도 와 달의 가장 큰 날 짜 를 얻 는 방법 은 어떻게 해 야 합 니까?
방법 은 다음 과 같이 바 꿀 수 있다.
public static Date getLastDay(int year, int month) {
Calendar c = Calendar.getInstance(); // Calendar
c.clear();
c.set(Calendar.YEAR, year); //
c.set(Calendar.MONTH, month - 1); // , 0 , month - 1
int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH); // ,
c.set(Calendar.DAY_OF_MONTH, lastDay); // Calendar
return c.getTime(); //
}
clear()방법 으로 Calendar 인 스 턴 스 의 필드 와 시간 을 정의 되 지 않 은 것 으로 설정 하면 이 문 제 를 해결 할 수 있 습 니 다.물론 인터넷 에서 도 달 을 다음 달 로 설정 하고 add(Calendar.DAYOF_MONTH,-1)이런 방법 도 결 과 를 얻 을 수 있 지만 여 기 는 자세히 소개 하지 않 겠 습 니 다.
자바 Calendar 클래스 set()방법의 함정 을 해결 하 는 방법 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 자바 Calendar set()내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 부탁드립니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.