자바 Calendar 클래스 set()방법의 함정 해결

6593 단어 JavaCalendarset()
프로젝트 에 서 는 지 정 된 연도 와 달의 마지막 날 을 가 져 와 야 합 니 다.나 는 인터넷 에서 Calendar 류 로 얻 는 방법 을 찾 았 다.코드 는 다음 과 같다.

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()내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기