본문 바로가기
JAVA

[JAVA][Date]두 날짜 사이의 기간 구하기

by Baley 2022. 2. 11.

[JAVA] 두 날짜 사이의 기간 구하기

1. 전체 예시 코드

public void betweenDates() {

    /* 기간 시작일 */
    String startDateStr = "2021-02-11";
    /* 기간 마감일 */
    String endDateStr = "2021-04-11";

    /**
    *  1) SimpleDateFormat 객체를 생성하면서 Date 데이터를 읽을 수 있는 패턴을 입력한다.
    */
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

    try {
        /**
        * 2) 생성한 SimpleDateFormat 객체의 parse 메소드를 통해 String을 Date로 형 변환한다.
         */
        Date startDate = formatter.parse(startDateStr);
        Date endDate = formatter.parse(endDateStr);

        /**
         *  3) Date의 getTime 메소드를 통해 해당 날짜들을 milliseconds로 변환한 다음
         *     마감일에서 시작일을 뺀다.
         *     어느 것이 마감일이고 시작일인지 모를 경우, Math.abs()를 통해 절댓값을 구한다.
         */
        long duration = endDate.getTime() - startDate.getTime();
        long durationAbsolute = Math.abs(startDate.getTime() - endDate.getTime());

        /**
         * 4) milliseconds에 1000, 60 , 60,  24를 나눠서 일 단위로 바꾼다.
         */
        long days = duration / (1000 * 60 * 60 * 24);

        /**
         * 5. 필요할 경우 int로 캐스팅한다.
         */
        int daysInt = Math.toIntExact(days);

		/* 출력 */
        System.out.println("startDate: " + startDate);
        System.out.println("endDate: " + endDate);
        System.out.println("duration: " + duration);
        System.out.println("durationAbsolute: " + durationAbsolute);
        System.out.println("long days: " + days);
        System.out.println("int days: " + daysInt);

    } catch (ParseException e) {
        e.printStackTrace();
    }

}

 

2. 과정

[조건] String 타입의 두 날짜 데이터가 있을 경우

/* 기간 시작일 */
String startDateStr = "2021-02-11";
/* 기간 마감일 */
String endDateStr = "2021-04-11";

 

1) SimpleDateFormat 객체를 패턴과 함께 생성한다.

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

 

 String 타입에서 Date 타입으로, Date 타입에서 String 타입으로 변환하는 것을 지원하는 SimpleDateFormat 클래스를 import한다. 그리고 formatter라는 변수에 SimpleDateFormat 객체를 생성한다.

 SimpleDateFormat은 생성할 때 인수로 패턴을 넣으면 해당 패턴에 맞춰 데이터를 해석한다. Date 타입으로 변환하고자 하는 String 타입에 맞춰 패턴을 작성한다.

 

https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html

 

SimpleDateFormat (Java Platform SE 8 )

Parses text from a string to produce a Date. The method attempts to parse text starting at the index given by pos. If parsing succeeds, then the index of pos is updated to the index after the last character used (parsing does not necessarily use all charac

docs.oracle.com

 

 

2) parse 메소드를 이용해 String은 Date 타입으로 변환한다.

try {
	Date startDate = formatter.parse(startDateStr);
	Date endDate = formatter.parse(endDateStr);
} catch (ParseException e) {
        e.printStackTrace();
    }

 

 *1, *2는 헷갈리지 않기 위한 표시

 생성된 객체(formatter)에서 parse 메소드(*1)를 이용하면 String 타입이 Date 타입으로 변환되어 리턴된다.

 여기서 이용되는 parse 메소드(*1)는 SimpleDateFormat에서 정의된 것이 아니다. SimpleDateFormat은 DateFormat이라는 추상 클래스를 상속받기 때문에 DateFormat에 구현되어 있는 parse 메소드(*1)를 사용할 수 있다.

 SimpleDateFormat에도 parse 메소드(*2)를 오버라이드해서 정의했지만 해당 메소드는 String 뿐만 아니라 ParsePosition이라는 두 개의 인수를 가지는 또 다른 parse 메소드(*2)를 오버라이드 한 것이다. 따라서 현재 사용하는 메소드는 DateFormat의 String 인수 하나를 받는 parse 메소드(*1)를 사용한 것이다.

 이 메소드(*1)는 ParseExpection를 throws 하므로 try - catch 문 안에 들어간다.

 

https://docs.oracle.com/javase/8/docs/api/java/text/DateFormat.html#parse-java.lang.String-

 

DateFormat (Java Platform SE 8 )

Parses text from a string to produce a Date. The method attempts to parse text starting at the index given by pos. If parsing succeeds, then the index of pos is updated to the index after the last character used (parsing does not necessarily use all charac

docs.oracle.com

 

 

3) Date 타입으로 변환된 두 데이터에 getTime 메소드를 사용한 뒤, 두 값의 차이를 구한다.

어느 쪽이 더 큰지 모르겠다면 Math.abs 를 이용해 절댓값을 구한다.  

long duration = endDate.getTime() - startDate.getTime();
long durationAbsolute = Math.abs(startDate.getTime() - endDate.getTime());

 

 getTime 메소드는 해당 Date일로부터 1970년 1월 1일 00:00:00 GMT까지의 시간을 밀리 세컨드로 구한다.

따라서 1970년 1월1일부터 기간 시작일까지의 시간, 1970년 1월 1일부터 기간 마감일까지의 시간을 빼면 시작일부터 마감일까지의 시간을 밀리 세컨드로 구할 수 있다. 

 

4) 밀리세컨드 변환값을 일 단위로 바꾼다.

 long days = duration / (1000 * 60 * 60 * 24);

초 : 밀리세컨드 / 1000

분 : 초 / 60

시간 : 분 / 60

일 : 시간 / 24

를 이용하면 일 단위를 구할 수 있다.

 

 

+5) 필요에 따라 int로 변환한다.

int daysInt = Math.toIntExact(days);

 

long을 int로 변환할 경우 overflow가 일어날 수 있으므로 overflow가 일어나는 경우 exception을 발생시키는 Math.toIntExact메소드를 사용할 수 있다.

int daysInt = (int) days;

 

그럴 염려가 없는 경우는 간단하게 캐스팅할 수 있다.

 

 

3. 출력 결과

 

 

흔한 실수(사실 내가 한 실수) :

SimpleDateFormat 객체를 생성할 때 패턴 입력에 유의한다. 'yyyy-mm-dd'로 입력할 경우 m은 분'minuate' 이므로 정확한 계산이 되지 않는다. 

SimpleDateFormat의 doc을 참조하자.

댓글