자바의 정석 3판 (10) 연습문제 : 날짜와 시간 & 형식화

NtoZ·2023년 3월 26일
0

Java

목록 보기
19/23
post-thumbnail

자바의 정석 3판 Chapter 10.


💡💡 10-1. 2010년의 매월 두 번째 일요일의 날짜 출력하기

  • 예제
//[10-1] Calendar클래스와 SimpleDateFormat클래스를 이용해서 
// 2010년의 매월 두 번째 일요일의 날짜를 출력하시오.

/*
<실행결과>
2010-01-10은 2번째 일요일입니다.
2010-02-14은 2번째 일요일입니다.
2010-03-14은 2번째 일요일입니다.
2010-04-11은 2번째 일요일입니다.
2010-05-09은 2번째 일요일입니다.
2010-06-13은 2번째 일요일입니다.
2010-07-11은 2번째 일요일입니다.
2010-08-08은 2번째 일요일입니다.
2010-09-12은 2번째 일요일입니다.
2010-10-10은 2번째 일요일입니다.
2010-11-14은 2번째 일요일입니다.
2010-12-12은 2번째 일요일입니다.

 */
  • <풀이접근1>💡 일정한 형식으로 반복되는 날짜를 계산하고 싶을 때는 Calendar 클래스의 add(속성, 증감값)를 사용하는 것이 좋다. 💡 이럴 때는 그 기준이 존재해야 한다. 보통 처음 그 해 연도의 1월 1일으로 세팅하고 add를 통해서 일정 값을 증감시켜 주는 것이 필요하다.

  • <접근방식1>

  1. Calendar 객체를 생성하여 연, 월, 일에 대한 정보를 초기화해야한다.
  2. SimpleDateFormat 생성자에 일정 포맷을 지정한 객체를 생성한다.
  3. DateFormat.format(Date d)이 매개변수로 Date d를 요구하므로, Calendar를 Date로 변환한다. (⭐Cal객체.getTime()으로 Date 타입으로 변환 가능)
  4. 💡날짜의 반복이 필요하므로, 반복문의 기준점이 별도로 필요하다. 1월 1일을 기준으로 잡고, add로 일요일이 되도록 한다.
  5. 2주차의 일요일을 구하려면 다시 add를 사용해 첫 번째 일요일에서 +7을 더하도록 한다. 그럼 두 번째 일요일이 된다.
  6. 이제 add를 사용해 Month를 +1씩 증가시켜서 12월(Month기준으로는 11)까지 반복문이 돌게 한다. ➡️ 여기서 문제가 발생한다. +1개월씩 해주는 것이므로 요일까지 맞춤으로 증가하는 것은 아니다.
    ➡️ 매월 마다 2번째 일요일을 찾아주는 반복문이 필요하다. add()로 더해서 해결할 수는 없다.
❌❌❌❌❌❌❌
public static void main(String[] args) {
        // 달력 객체 생성하여 cal에 저장, SimpleDateFormat객체 생성하여 df에 저장
        Calendar cal = Calendar.getInstance();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //⭐MM이 달이고 mm이 분이다. 헷갈리지 말자!
        cal.set(2010,00,1); //⭐ cal객체의 달력을 2010년 01월 01일로 맞춤.
        System.out.println(cal);
        for (int i=1; i<=7; i++) {
            if(cal.get(Calendar.DAY_OF_WEEK)== Calendar.SUNDAY) {  //⭐순회해서 DAY_OF_WEEK 값이 일요일이면 for문 끝냄.
                break;  //return이 아니라 break를 써야 main메서드를 탈출하는 것이 아닌 for문을 탈출함.
            }
            cal.add(Calendar.DAY_OF_MONTH, 1);      //⭐날짜를 하루씩 증가시키면서 일요일 찾기
        }
        //⭐ 2010년 1월의 첫 번째 일요일이 cal에 저장된 상태에서 두 번째 일요일을 구하려면 날짜를 +7 해주고, 각 개월의 두 번째 일요일을 구하려면 거기서 ~~+31해야한다.~~ ⭐⭐아니다. 모든 일수가 동일하지 않기때문에 달을+1한다.
        cal.add(Calendar.DAY_OF_MONTH, 7);  //⭐ 1월의 두 번째 일요일
        System.out.println(cal);
        for(int month=0; month<12; month++) {
            System.out.printf(df.format(cal.getTime())+"은 %d번째 %d요일입니다.%n", cal.get(Calendar.DAY_OF_WEEK_IN_MONTH), cal.get(Calendar.DAY_OF_WEEK));
            cal.add(Calendar.MONTH, 1); //⭐한 달씩 증가.❌❌❌ 요일까지 맞춰 증가하는게 아니다
        }
    }
<해당코드 실행결과>
2010-01-102번째 1요일입니다.
2010-02-102번째 4요일입니다.
2010-03-102번째 4요일입니다.
2010-04-102번째 7요일입니다.
2010-05-102번째 2요일입니다.
2010-06-102번째 5요일입니다.
2010-07-102번째 7요일입니다.
2010-08-102번째 3요일입니다.
2010-09-102번째 6요일입니다.
2010-10-102번째 1요일입니다.
2010-11-102번째 4요일입니다.
2010-12-102번째 6요일입니다.
❌❌❌❌❌❌❌
  • <접근방식2>
  1. Calendar 객체를 생성하여 연, 월, 일에 대한 정보를 초기화해야한다.
  2. SimpleDateFormat 생성자에 일정 포맷을 지정한 객체를 생성한다.
  3. DateFormat.format(Date d)이 매개변수로 Date d를 요구하므로, Calendar를 Date로 변환한다. (⭐Cal객체.getTime()으로 Date 타입으로 변환 가능)
  4. 날짜의 반복이 필요하다. ⭐반복문(while 조건)으로 매월 1일을 세팅한 후, 2번째 일요일을 구해서 출력하도록 하자.
class Sol_Exercise10_1 {
    public static void main(String[] args) {
        // 달력 객체 생성하여 cal에 저장, SimpleDateFormat객체 생성하여 df에 저장
        Calendar cal = Calendar.getInstance();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //⭐MM이 달이고 mm이 분이다. 헷갈리지 말자!
        cal.set(2010,00,1); //⭐ cal객체의 달력을 2010년 01월 01일로 맞춤.
        
        //while(cal.get(Calendar.MONTH)<11) {    //❗❗무한 루프 때문에 사용불가 (Month에서 11+1=0이 되버린다.)
        int month=1;    //⭐ 무한루프 방지용 변수
        while(true) {
            cal.add(Calendar.DAY_OF_MONTH, 1);  // 날짜를 1씩 증가시켜서
            if(cal.get(Calendar.DAY_OF_WEEK)== Calendar.SUNDAY) {  //⭐ cal객체의 요일이 일요일이면
                cal.add(Calendar.DAY_OF_MONTH, 7);  // 일주일 증가시키면 두 번째 일요일.
                System.out.printf("%s은 %d번째 일요일입니다.%n",
                                    df.format(cal.getTime()),
                                    cal.get(Calendar.DAY_OF_WEEK_IN_MONTH));    //값을 출력하고
                cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, 1);    //⭐다음 달 1일로 초기화 ⭐⭐단, MONTH가 11일때 +1하게 되면 =>0로 바뀐다. (무한루프주의)
                month++;    //⭐ 무한루프 방지용 변수
                if (month>12) { //⭐ 무한루프 방지
                break;
                }
            }
        }
    }
}
<답안>
2010-01-102번째 일요일입니다.
2010-02-142번째 일요일입니다.
2010-03-142번째 일요일입니다.
2010-04-112번째 일요일입니다.
2010-05-092번째 일요일입니다.
2010-06-132번째 일요일입니다.
2010-07-112번째 일요일입니다.
2010-08-153번째 일요일입니다.
2010-09-122번째 일요일입니다.
2010-10-102번째 일요일입니다.
2010-11-142번째 일요일입니다.
2010-12-122번째 일요일입니다.
  • <모범풀이>
import java.util.*;
import java.text.*;

class Exercise10_1
{
    public static void main(String[] args)
    {
        Calendar cal = Calendar.getInstance();

        cal.set(2010,0,1); // cal의 날짜를 2010년 1월 1일로 설정한다.

        for(int i=0; i < 12;i++) {
            int weekday = cal.get(Calendar.DAY_OF_WEEK); // 1일의 요일을 구한다.

// ⭐두 번째 일요일은 1일의 요일에 따라 달라진다.
// ⭐1일이 일요일인 경우에는 두번째 일요일은 8일이고,
// ⭐1일이 다른 요일일 때는 16에서  1일의 요일(weekday)을 빼면 알 수 있다. 
            int secondSunday = (weekday==1) ? 8 : 16 - weekday;

// 두 번째 일요일(secondSunday)로 cal의 날짜(DAY_OF_MONTH)를 바꾼다. 
            cal.set(Calendar.DAY_OF_MONTH, secondSunday);

            Date d = cal.getTime(); // Calendar를 Date로 변환한다.
            System.out.println(new SimpleDateFormat("yyyy-MM-dd은 F번째 E요일입니다.").format(d));

// 날짜를 다음달 1일로 변경한다.
            cal.add(Calendar.MONTH, 1);
            cal.set(Calendar.DAY_OF_MONTH,1);
        }
    }
}
  • 풀이 다른 점:
    [해설] 매월 두 번째 일요일(secondSunday)을 구하려면, 매월 1일이 무슨 요일인지 알아내야한다. 만일 1일이 일요일이라면
    2번째 일요일은 8일이 된다. 1일이 월요일이라면 2번째 일요일은 14일이 된다. 1일이 일요일인 경우를 제외하고는 1일의 요일(weekday)과 2번째 일요일의 날짜를 더하면 일정한 값(16)이라는 것을 알 수 있다.
    💡즉, 16에서 1일의 요일(weekday)을 빼면 2번째 일요일이 며칠인지 알 수 있는 것이다.(1일이 일요일인 경우 에는 9에서 1을 뺀 8이 된다.)
    int secondSunday = (weekday==1) ? 8 : 16 - weekday;

    이제 두 번째 일요일의 날짜(secondSunday)를 알아냈으니, set()를 사용해서 cal의 날짜(DAY_OF_MONTH)를 두 번째 일요일의 날짜로 변경한다. SimpleDateFormat클래스의 format 메서드는 매개변수로 Date타입을 받기 때문에 cal.getTime()을 호출해서 Calendar를 Date 로 변환해야한다.
// 두 번째 일요일(secondSunday)로 cal의 날짜(DAY_OF_MONTH)를 바꾼다. cal.set(Calendar.DAY_OF_MONTH, secondSunday);

Date d = cal.getTime(); // Calendar를 Date로 변환한다.
System.out.println(new SimpleDateFormat("yyyy-MM-dd은 
F번째 E요일입니다.").format(d));	//⭐F번째 E요일 기호 사용
  • 💡💡 new SimpleDateFormat(패턴문자열)객체에 패턴을 지정하고 바로 format(Date d)메서드를 활용해 형식화 해버릴 수 있다.
    - e.g.
    F번째 E요일이라는 기호를 사용해서 객체 cal에 저장된 iv값을 출력할 수 있다.
    new SimpleDateFormat("yyyy-MM-dd은 F번째 E요일입니다.").format(d)

10-2. 특정 기간동안 특정 일자가 몇 번 반복되는지 확인하기

  • 예제
//[10-2] 어떤 회사의 월급날이 매월 21일이다. 두 날짜 사이에 월급날이 몇 번있는지 계산해서 반환하는 메서드를 작성하고 테스트 하시오.

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

class Exercise10_2 {
    static int paycheckCount(Calendar from, Calendar to) {
    /*
    (1) 아래의 로직에 맞게 코드를 작성하시오.
    1.	from 또는 to가 null이면 0을 반환한다.
    2.	from와 to가 같고 날짜가 21일이면 1을 반환한다.
    3.	to와 from이 몇 개월 차이인지 계산해서 변수 monDiff에 담는다.
    4.	monDiff가 음수이면 0을 반환한다.
    5.	만일 from의 일(DAY_OF_MONTH)이 21일이거나 이전이고
    to의 일(DAY_OF_MONTH)이 21일이거나 이후이면 monDiff의 값을 1 증가시킨다.
    6.	만일 from의 일(DAY_OF_MONTH)이 21일 이후고
    to의 일(DAY_OF_MONTH)이 21일 이전이면 monDiff의 값을 1 감소시킨다.
    */

        return monDiff;
    }

    static void printResult(Calendar from, Calendar to) {
        Date fromDate = from.getTime();
        Date toDate = to.getTime();

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

        System.out.print(sdf.format(fromDate)+" ~ "
                +sdf.format(toDate)+":"); System.out.println(paycheckCount(from, to));
    }

    public static void main(String[] args) { Calendar fromCal = Calendar.getInstance(); Calendar toCal = Calendar.getInstance();

        fromCal.set(2010,0,1); toCal.set(2010,0,1); printResult(fromCal, toCal);

        fromCal.set(2010,0,21); toCal.set(2010,0,21); printResult(fromCal, toCal);

        fromCal.set(2010,0,1); toCal.set(2010,2,1); printResult(fromCal, toCal);

        fromCal.set(2010,0,1); toCal.set(2010,2,23); printResult(fromCal, toCal);

        fromCal.set(2010,0,23); toCal.set(2010,2,21); printResult(fromCal, toCal);

        fromCal.set(2011,0,22); toCal.set(2010,2,21); printResult(fromCal, toCal);

    }
}

/*
<실행결과>
2010-01-01 ~ 2010-01-01:0
2010-01-21 ~ 2010-01-21:1
2010-01-01 ~ 2010-03-01:2
2010-01-01 ~ 2010-03-23:3
2010-01-23 ~ 2010-03-21:2
2011-01-22 ~ 2010-03-21:0
 */
  • ❌문제 풀이1
class Sol_Exercise10_2 {
    static int paycheckCount(Calendar from, Calendar to) {
    /*
    (1) 아래의 로직에 맞게 코드를 작성하시오.
    1.	from 또는 to가 null이면 0을 반환한다.
    2.	from와 to가 같고 날짜가 21일이면 1을 반환한다.
    3.	to와 from이 몇 개월 차이인지 계산해서 변수 monDiff에 담는다.
    4.	monDiff가 음수이면 0을 반환한다.
    5.	만일 from의 일(DAY_OF_MONTH)이 21일이거나 이전이고
    to의 일(DAY_OF_MONTH)이 21일이거나 이후이면 monDiff의 값을 1 증가시킨다.
    6.	만일 from의 일(DAY_OF_MONTH)이 21일 이후고
    to의 일(DAY_OF_MONTH)이 21일 이전이면 monDiff의 값을 1 감소시킨다.
    */
        if(from==null || to==null) return 0;    // null값이 아니어야 함
        if(from==to && from.get(Calendar.DAY_OF_MONTH)==21) return 1;   //Date가 같고 일자가 21이면 1 반환
        int monDiff = (int)((to.getTimeInMillis()-from.getTimeInMillis())/(1000*60*60*24*30)); //->s->m->h->day->month ⭐그러나 month는 항상 30일인것이 아니다.
        System.out.println(monDiff);
        if(monDiff<0) return 0; //to가 from보다 이전일이면 0을 반환
        if((from.get(Calendar.DAY_OF_MONTH)<=21)&&(to.get(Calendar.DAY_OF_MONTH)>=21)) monDiff++;
        if((from.get(Calendar.DAY_OF_MONTH)>21)&&(to.get(Calendar.DAY_OF_MONTH)<21)) monDiff--;
        return monDiff;
    }

    static void printResult(Calendar from, Calendar to) {
        Date fromDate = from.getTime();
        Date toDate = to.getTime();

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

        System.out.print(sdf.format(fromDate)+" ~ "
                +sdf.format(toDate)+":"); System.out.println(paycheckCount(from, to));
    }

    public static void main(String[] args) { Calendar fromCal = Calendar.getInstance(); Calendar toCal = Calendar.getInstance();

        fromCal.set(2010,0,1); toCal.set(2010,0,1); printResult(fromCal, toCal);

        fromCal.set(2010,0,21); toCal.set(2010,0,21); printResult(fromCal, toCal);

        fromCal.set(2010,0,1); toCal.set(2010,2,1); printResult(fromCal, toCal);

        fromCal.set(2010,0,1); toCal.set(2010,2,23); printResult(fromCal, toCal);

        fromCal.set(2010,0,23); toCal.set(2010,2,21); printResult(fromCal, toCal);

        fromCal.set(2011,0,22); toCal.set(2010,2,21); printResult(fromCal, toCal);

    }
}

<결과값>
2010-01-01 ~ 2010-01-01:0
0
2010-01-21 ~ 2010-01-21:0
1
2010-01-01 ~ 2010-03-01:-2
0
2010-01-01 ~ 2010-03-23:-4
0
2010-01-23 ~ 2010-03-21:-2
0
2011-01-22 ~ 2010-03-21:15
15
  • 문제 접근:
    원래 ⭐두 시간의 차를 구할 때 Calendar.getTimeInMillis()의 차이를 이용했다. ⭐그러나 이 방식대로는 최대 단위 '일'까지만 정확히 환산할 수 있다. (차이의 ms)/(1000초*60분*60시간*24일)
    왜냐하면 한 달은 최소 28일부터 최대31일까지 다양하기 때문이다.

  • 따라서 두 시간의 차이를 '월' 단위에서 구하려면
    💡from과 to의 연, 월을 따로 구하여 연*12+월의 시간차를 구하자!

  • 또한 5~6번에서 사용될 일자간 비교에서는 to의 일자와 from의 일자를 각각 구하여 따로 비교해주면 된다.

  • 문제 풀이 :

class Sol_Exercise10_2 {
    static int paycheckCount(Calendar from, Calendar to) {
    /*
    (1) 아래의 로직에 맞게 코드를 작성하시오.
    1.	from 또는 to가 null이면 0을 반환한다.
    2.	from와 to가 같고 날짜가 21일이면 1을 반환한다.
    3.	to와 from이 몇 개월 차이인지 계산해서 변수 monDiff에 담는다.
    4.	monDiff가 음수이면 0을 반환한다.
    5.	만일 from의 일(DAY_OF_MONTH)이 21일이거나 이전이고
    to의 일(DAY_OF_MONTH)이 21일이거나 이후이면 monDiff의 값을 1 증가시킨다.
    6.	만일 from의 일(DAY_OF_MONTH)이 21일 이후고
    to의 일(DAY_OF_MONTH)이 21일 이전이면 monDiff의 값을 1 감소시킨다.
    */
        if(from==null || to==null) return 0;    //1. null값이 아니어야 함
        if(from==to && from.get(Calendar.DAY_OF_MONTH)==21) return 1;   //2. Date가 같고 일자가 21이면 1 반환, eqauls()를 사용하여도 됨.

        //3.monDiff와 5~6에 사용할 변수 만들기
        int toYear = to.get(Calendar.YEAR);
        int toMon = to.get(Calendar.MONTH);
        int toDay = to.get(Calendar.DAY_OF_MONTH);
        int fromYear = from.get(Calendar.YEAR);
        int fromMon = from.get(Calendar.MONTH);
        int fromDay = from.get(Calendar.DAY_OF_MONTH);

        int monDiff = (toYear*12+toMon) - (fromYear*12+fromMon);

        //4.
        if (monDiff<0) return 0;
        //5~6.
        if (fromDay<=21&&toDay>=21) monDiff++;
        if (fromDay>21&&toDay<21) monDiff--;

        return monDiff;
    }

    static void printResult(Calendar from, Calendar to) {
        Date fromDate = from.getTime();
        Date toDate = to.getTime();

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

        System.out.print(sdf.format(fromDate)+" ~ "
                +sdf.format(toDate)+":"); System.out.println(paycheckCount(from, to));
    }

    public static void main(String[] args) { Calendar fromCal = Calendar.getInstance(); Calendar toCal = Calendar.getInstance();

        fromCal.set(2010,0,1); toCal.set(2010,0,1); printResult(fromCal, toCal);

        fromCal.set(2010,0,21); toCal.set(2010,0,21); printResult(fromCal, toCal);

        fromCal.set(2010,0,1); toCal.set(2010,2,1); printResult(fromCal, toCal);

        fromCal.set(2010,0,1); toCal.set(2010,2,23); printResult(fromCal, toCal);

        fromCal.set(2010,0,23); toCal.set(2010,2,21); printResult(fromCal, toCal);

        fromCal.set(2011,0,22); toCal.set(2010,2,21); printResult(fromCal, toCal);

    }
}

/*
<실행결과>
2010-01-01 ~ 2010-01-01:0
2010-01-21 ~ 2010-01-21:1
2010-01-01 ~ 2010-03-01:2
2010-01-01 ~ 2010-03-23:3
2010-01-23 ~ 2010-03-21:2
2011-01-22 ~ 2010-03-21:0
*/


💡10-3. Number 클래스 특징

 String data = "123,456,789.5"; //data :123,456,789.5
        System.out.println("data :" + data);
        DecimalFormat df1 = new DecimalFormat("###,###.#");
        Number d = df1.parse(data); //⭐data의 형식문자열을 Number d로 내장된 패턴에 의거해 parse
        System.out.println("d :"+ d); //⭐d :1.234567895E8   
        //❓ parse 되었을 때 자동으로 지수표현이 붙는건가? Number클래스에는 지수부가 붙는구나!
  • ⭐Number 클래스로 parsing하면 자동으로 지수부가 붙는다. 이를 보기 좋도록 Double에 담을 때 double d = num.doubleValue(); 를 사용하면 d의 값이 1.234567895E8가 아니라 123456789.5가 된다.

⭐10-4. 화면으로부터 일정한 날짜 양식 입력받아 무슨 요일인지 출력하기

  • 예제
//[10-4] 화면으로부터 날짜를 “2007/05/11”의 형태로 입력받아서 무슨 요일인지 출력하 는 프로그램을 작성하시오.
//단, 입력된 날짜의 형식이 잘못된 경우 메세지를 보여주고 다시 입력받아야 한다.

/*
<실행결과>
날짜를 yyyy/MM/dd의 형태로 입력해주세요.(입력예:2007/05/11)
>>2009-12-12
날짜를 yyyy/MM/dd의 형태로 입력해주세요.(입력예:2007/05/11)
>>2009/12/12
입력하신 날짜는 토요일입니다.
 */
  • 풀이 접근 :
  1. "2007/05/11"은 형식화 문자열이라고 볼 수 있다.
  2. Date 날짜 형태로 다시 되돌리려면 SimpleDateFormat객체.parse(String 형식화문자열)을 사용해야 한다.
    입력된 날짜의 형식이 잘못된 경우 메시지를 보여주고 다시 입력받아야 하는데,
  3. parse 같은 경우에는 내부 형식이 잘못된 경우 ParseException 예외 객체를 호출하므로,
    반복문 안에서 해당 메서드를 사용하고 catch(ParseException) { }에서 다시 입력받으면 된다.
  4. Date 객체를 다시 형식화 할때는 new SimpleDateFormat(패턴).format(Date d)를 활용하면 된다.
  • 내 풀이
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;

class Sol_Exercise10_4 {
    static Scanner sc = new Scanner(System.in);

    static void dataProces() throws ParseException { //⭐ ParseException을 메인으로 넘겨줘서 처리하게 하는 이유? 잘못된 값을 입력받으면 다시 받을 수 있도록!
        System.out.println("날짜를 yyyy/MM/dd의 형태로 입력해주세요.(입력예:2007/05/11)");
        String input = sc.nextLine();
        //⭐ 일회용 객체를 생성하여 parse로 바로 Date화 함.
        Date date = new SimpleDateFormat("yyyy/MM/dd").parse(input);    //⭐ParseException 발생가능
        //⭐ Date 클래스 기능을 다시 형식화 하려면 SimpleDateFormat 객체가 필요하다.
        DateFormat df = new SimpleDateFormat("입력하신 날짜는 E요일 입니다.");
        System.out.println(df.format(date));
    }

    public static void main(String[] args) {

        while(true) {
            try {
                dataProces();
                break;//⭐ 출력이 정상적으로 완료되면 메서드를 끝내야 한다.
            } catch (ParseException e) {
                continue;
            }
        }

    }
}
  • ⭐⭐ 반복문을 사용해 예외 발생을 반복의 조건으로 이용할 수 있다.
  • <메서드 예외 선언하기>의 예시를 보여준다. 메소드 dateProcess()는 그 예외를 main단에서 처리해야 하므로 예외를 던지는 것을 선택했다.

10-5. 형식 문자열 넘겨 받아 두 날짜의 차이를 일(day)단위로 반환하기

  • 내 풀이
class Exercise10_5 {
/*
(1) getDayDiff메서드를 작성하시오.
*/
    static int getDayDiff(String yyyymmdd1, String yyyymmdd2) {
        Date d1 = null;
        Date d2 = null;
        try {
            d1 = new SimpleDateFormat("yyyyMMdd").parse(yyyymmdd1);
            d2 = new SimpleDateFormat("yyyyMMdd").parse(yyyymmdd2);
        } catch (ParseException e) {
            //⭐주어진 문자열이 유효하지 않으면 0을 반환 (⭐⭐예외를 이 메서드에서 해결함)
            return 0;
        }
        // ⭐각 Date를 getTimeInMills()로 나타내서 차이를 구하기 위해 Calendar화
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(d1);
        c2.setTime(d2);

        return (int)((c1.getTimeInMillis()-c2.getTimeInMillis())/(1000*60*60*24));
    }

    public static void main(String[] args){
        System.out.println(getDayDiff("20010103","20010101"));
        System.out.println(getDayDiff("20010103","20010103"));
        System.out.println(getDayDiff("20010103","200103"));
    }
}

<실행결과>
2
0
0
  • ⭐⭐ 예외를 메서드 안에서 해결하기를 선택했다. 10-5와 비교가 가능하다.

  • 모범답안

import java.util.*;

class Exercise10_5 {
    static int getDayDiff(String yyyymmdd1, String yyyymmdd2) { int diff = 0;

        try {
            int year1 = Integer.parseInt(yyyymmdd1.substring(0,4)); 
            int month1 = Integer.parseInt(yyyymmdd1.substring(4,6)) - 1; 
            int day1 = Integer.parseInt(yyyymmdd1.substring(6,8));

            int year2 = Integer.parseInt(yyyymmdd2.substring(0,4)); 
            int month2 = Integer.parseInt(yyyymmdd2.substring(4,6)) - 1; 
            int day2 = Integer.parseInt(yyyymmdd2.substring(6,8));

            Calendar date1 = Calendar.getInstance(); 
            Calendar date2 = Calendar.getInstance();

            date1.set(year1, month1, day1); 
            date2.set(year2, month2, day2);

            diff = (int)((date1.getTimeInMillis()-date2.getTimeInMillis())
                    /(24*60*60*1000));
        } catch(Exception e) {
            diff = 0; // substring(), parseInt()에서 예외가 발생하면 0을 반환한다.
        }

        return diff;
    }

    public static void main(String[] args){ 
        System.out.println(getDayDiff("20010103","20010101")); 
        System.out.println(getDayDiff("20010103","20010103")); 
        System.out.println(getDayDiff("20010103","200103"));
    }
}

/*
[해설] 넘겨받은 문자열을 substring()으로 잘라서 년, 월, 일을 각각 구한 다음,
        이 값들을 가지고 Calendar의 년월일을 설정한다.
[참고] Calendar클래스의 month값은 1이 아닌 0부터 시작하기 때문에 1을 빼주어야 한다.

        int year1 = Integer.parseInt(yyyymmdd1.substring(0,4)); 
        int month1 = Integer.parseInt(yyyymmdd1.substring(4,6)) - 1; 
        int day1 = Integer.parseInt(yyyymmdd1.substring(6,8));

        Calendar date1 = Calendar.getInstance(); date1.set(year1, month1, day1);

        Calendar의 getTimeInMillis()는 날짜를 천분의 일초단위로 변환해서 반환한다. getTime
        Millis()를 이용해서 두 날짜를 천분의 일초로 변환해서 차이를 구한 다음에 일(day) 단 위로 변환하면 두 날짜의 날(day) 차이를 구할 수 있다.
        천분의 일초 단위를 일 단위로 바꾸려면 24*60*60*1000로 나눠주면 된다.
        (1일 = 24시간 = 24*60분 = 24*60*60초 = 24*60*60*1000밀리세컨드)

        date1.set(year1, month1, day1); date2.set(year2, month2, day2);

        diff = (int)((date1.getTimeInMillis()-date2.getTimeInMillis())
        /(24*60*60*1000));
*/

10-6. 현재 날짜와 생일의 기간차이 며칠(d) 단위로 나타내기

  • 내 풀이
//[10-6] 자신이 태어난 날부터 지금까지 며칠이 지났는지 계산해서 출력하시오.

/*
<실행결과>
birth day=2000-01-01
today	=2016-01-29
5872 days

 */

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

class Sol_Exercise10_6 {
    public static void main(String[] args) throws ParseException {
        String birth = "2000-01-01";
        String today = "2016-01-29";

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Date dateBirth = df.parse(birth);
        Date dateToday = df.parse(today);

        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();

        c1.setTime(dateBirth);
        c2.setTime(dateToday);

        //⭐ 며칠이 지났는지는 getTimeInMills()의 차이를 통해 구할 수 있다.
        long diff = ((c2.getTimeInMillis()-c1.getTimeInMillis())/(1000*60*60*24));  // 1995-10-27 ⭐ms는 초,분,시,일로 반드시 나누어 떨어짐.

        System.out.println(
                "birthday="+birth+"\n"+
                "today="+today+"\n"+
                diff+"days");
    }
}
  • 정답 : 💡java.time 패키지의 LocalDate 이용하기
💡java.time 패키지의 LocalDate 이용하기
import java.time.*;
        import java.time.temporal.*;

class Exercise10_6 {
    public static void main(String[] args) {
        LocalDate birthDay = LocalDate.of(2000, 1, 1); // 자신의 생일을 지정
        LocalDate now	= LocalDate.now();

        long days = birthDay.until(now, ChronoUnit.DAYS);

        System.out.println("birth day="+birthDay); System.out.println("today	="+now); System.out.println(days +" days");
    }
}

💡10-7. ?째주 ?요일의 날짜 구하기

  • 문제 풀이:
<// [10-7] 2016년 12월 네번째 화요일의 날짜를 아래의 실행결과와 같은 형식으로 출력하시오.

/*
<실행결과>
2016-12-27
 */

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

class Sol_Exercise10_7 {
    public static void main(String[] args) {
        Calendar c1 = Calendar.getInstance();
        c1.set(2016, 11, 1);    //⭐⭐ Month는 항상 -1을 붙여야 한다는 사실을 잊지말자!
        while (true) {
            if(c1.get(Calendar.DAY_OF_WEEK)==3) {   //첫 번째 화요일
                c1.add(Calendar.DAY_OF_MONTH, 21);  //3주 뒤 (4번째 화요일 날짜)
                String result = new SimpleDateFormat("yyyy-MM-dd").format(c1.getTimeInMillis());
                System.out.println(result);
                break;
            }
            c1.add(Calendar.DAY_OF_MONTH, 1);
        }
    }
}

/*
<풀이 접근>
1. 2016년 1월 1일로 Calendar객체 set.
2. DAY_OF_WEEK가 3(화)이 나오는 순간을 날짜를 하나씩 add해가며 찾는다.
3. 해당 날짜 + 21일이 3주 뒤의 네 번째 화요일이므로 add(일, 21)을 한다.
4. DateFormat으로 "2016-12-27" 패턴을 통해 format(d)한다.

 */
  • 💡모범풀이:
    💡[정답] ?째주 ?요일은 TemporalAdjusters클래스의 dayOfWeekInMonth()를 이용하면 된다.
/*
<정답 풀이>
💡[정답] ?째주 ?요일은 TemporalAdjusters클래스의 dayOfWeekInMonth()를 이용하면 된다.
 */
 import java.time.*;
        import static java.time.DayOfWeek.*;
        import static java.time.temporal.TemporalAdjusters.*;

class Exercise10_7 {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2016, 12, 1);
        System.out.println(date.with(dayOfWeekInMonth(4, TUESDAY)));
    }
}

💡10-8. 서울과 뉴욕간의 시차 구하기

  • 문제
//[10-8] 서울과 뉴욕간의 시차가 얼마인지 계산하여 출력하시오.

/*
<실행결과>
2016-01-28T23:01:00.136+09:00[Asia/Seoul]
2016-01-28T09:01:00.138-05:00[America/New_York] sec1=32400
sec2=-18000
diff=14 hrs

 */
  • 모범 풀이
class Exercise10_8 {
    public static void main(String[] args) { 
        ZonedDateTime zdt = ZonedDateTime.now(); 
        ZoneId nyId = ZoneId.of("America/New_York");
        ZonedDateTime zdtNY = ZonedDateTime.now().withZoneSameInstant(nyId);

        System.out.println(zdt); System.out.println(zdtNY);

        long sec1 = zdt.getOffset().getTotalSeconds(); 
        long sec2 = zdtNY.getOffset().getTotalSeconds();
        long diff = (sec1 - sec2)/3600;

        System.out.println("sec1="+sec1); 
        System.out.println("sec2="+sec2); 
        System.out.printf("diff=%d hrs%n",diff);
    }
}

<정답>
[해설]
 
ZonedDateTimegetOffset()ZoneOffset을 반환한다.	
ZoneOffsetgetTotalSeconds()를 호출하면, 날짜와 시간을 
초단위로 변환한 결과를 얻을 수 있다.

ZoneOffset offset = zdt.getOffset();
long sec1 = offset.getTotalSeconds();

현재 서울과 뉴욕의 날짜와 시간을 초단위로 바꾼다음에, 
차이를 구하면 시차를 초단위로 구할 수 있다. 
이 값을 3600(1시간)으로 나누면, 시간단위의 값을 구할 수 있다.
profile
9에서 0으로, 백엔드 개발블로그

0개의 댓글