본문 바로가기

Java/자바 기초

10. 날짜와 시간 & 형식화

날짜와 시간

java.util.Date

날짜와 시간을 다룰 목적으로 JDK1.0부터 제공된 클래스이며, Date의 메서드는 대부분 deprecated되었지만, 여전히 쓰이고 있다.

 

java.util.Calendar

Date클래스를 개선한 클래스로 JDK1.1부터 제공되었지만, 몇 가지 단점이 존재한다.

 

java.time패키지

기존의 Data클래스와 Calendar클래스의 단점을 개선한 새로운 클래스들이 JDK1.8부터 추가되었다.

 

새로 추가된 java.time패키지만 배우면 좋을 텐데, 아쉽게도 Calender와 Date는 자바의 탄생부터 지금까지 20년 넘게 사용되어왔고, 지금도 계속 사용되고 있으므로 배우지 않고 넘어갈 수 없다.

Calender와 Date의 기능은 소소한 예제들을 이해하고 필요할 때 활용하는 정도면 충분하다.

Calendar클래스

Calnedar클래스는 추상클래스이기 때문에 직접 객체를 생성할 수 없고, getInstance메서드를 통해서 완전히 구현된 객체를 얻어야 한다.

Calendar cal = new Calendar( ); //에러! 추상클래스는 인스턴스를 생성할 수 없다.

// OK, getInstance()메서드는 Calender클래스를 구현한 클래스의 인스턴스를 반환한다.
Calender cal = Calender.getInstance();

Calendar 예제1

Calendar 클래스에 정의된 static 상수 필드

import java.util.*;

class Ex10_1 {
    public static void main(String[] args) 
    {  // 기본적으로 현재날짜와 시간으로 설정된다.
        Calendar today = Calendar.getInstance();    
        System.out.println("이 해의 년도 : " + today.get(Calendar.YEAR));
        System.out.println("월(0~11, 0:1월): " + today.get(Calendar.MONTH));
          System.out.println("이 해의 몇 째 주: " 
                                    + today.get(Calendar.WEEK_OF_YEAR)); 
        System.out.println("이 달의 몇 째 주: " 
                                    + today.get(Calendar.WEEK_OF_MONTH));
        // DATE와 DAY_OF_MONTH는 같다.
         System.out.println("이 달의 몇 일: " + today.get(Calendar.DATE));
         System.out.println("이 달의 몇 일: " + today.get(Calendar.DAY_OF_MONTH));
        System.out.println("이 해의 몇 일: " + today.get(Calendar.DAY_OF_YEAR));
          System.out.println("요일(1~7, 1:일요일): " 
         + today.get(Calendar.DAY_OF_WEEK)); // 1:일요일, 2:월요일, ... 7:토요일
         System.out.println("이 달의 몇 째 요일: "
                               + today.get(Calendar.DAY_OF_WEEK_IN_MONTH));
        System.out.println("오전_오후(0:오전, 1:오후): "
                               + today.get(Calendar.AM_PM));
        System.out.println("시간(0~11): " + today.get(Calendar.HOUR));
        System.out.println("시간(0~23): " + today.get(Calendar.HOUR_OF_DAY));
        System.out.println("분(0~59): " + today.get(Calendar.MINUTE));
        System.out.println("초(0~59): " + today.get(Calendar.SECOND));
        System.out.println("1000분의 1초(0~999): " 
                                      + today.get(Calendar.MILLISECOND));
         // 천분의 1초를 시간으로 표시하기 위해 3600000으로 나누었다.(1시간 = 60 * 60초)
        System.out.println("TimeZone(-12~+12): " 
                    + (today.get(Calendar.ZONE_OFFSET)/(60*60*1000))); 
        System.out.println("이 달의 마지막 날: " 
            + today.getActualMaximum(Calendar.DATE) ); // 이 달의 마지막 일을 찾는다.
    }
}

/*
출력 결과

이 해의 년도 : 2022
월(0~11, 0:1월): 1
이 해의 몇 째 주: 9
이 달의 몇 째 주: 4
이 달의 몇 일: 22
이 달의 몇 일: 22
이 해의 몇 일: 53
요일(1~7, 1:일요일): 3
이 달의 몇 째 요일: 4
오전_오후(0:오전, 1:오후): 0
시간(0~11): 10
시간(0~23): 10
분(0~59): 18
초(0~59): 12
1000분의 1초(0~999): 795
TimeZone(-12~+12): 0
이 달의 마지막 날: 28

*/

주의해야할 것은 get(Calendar.MONTH)로 얻어오는 값의 범위가 1~12가 아닌 0~11이라는 것이다. 그래서 get(Calendar.MONTH)로 얻어오는 값이 0이면 1월을 의미하고, 11이면 12월을 의미한다.

Calendar 예제2

import java.util.*;

class Ex10_2 {
    public static void main(String[] args) {
        // 요일은 1부터 시작하기 때문에, DAY_OF_WEEK[0]은 비워두었다.
        final String[] DAY_OF_WEEK = {"","일","월","화","수","목","금","토"};

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

        // month의 경우 0부터 시작하기 때문에 4월인 경우, 3로 지정해야한다.
        // date1.set(2019, Calendar.APRIL, 29);와 같이 할 수도 있다.
        date1.set(2019, 3, 29); // 2019년 4월 29일로 날짜를 설정한다. 
        System.out.println("date1은 "+ toString(date1) 
                  + DAY_OF_WEEK[date1.get(Calendar.DAY_OF_WEEK)]+"요일이고,");
        System.out.println("오늘(date2)은 " + toString(date2) 
                 + DAY_OF_WEEK[date2.get(Calendar.DAY_OF_WEEK)]+"요일입니다.");

       // 두 날짜간의 차이를 얻으려면, getTimeInMillis() 천분의 일초 단위로 변환해야한다.
         //초단위로 얻기 위해 100을 나눠주어야 한다.
       long difference = 
            (date2.getTimeInMillis() - date1.getTimeInMillis())/1000; 
        System.out.println("그 날(date1)부터 지금(date2)까지 "
                                           + difference +"초가 지났습니다.");
        System.out.println("일(day)로 계산하면 "+ difference/(24*60*60) 
                                     +"일입니다."); // 1일 = 24 * 60 * 60
    }

    public static String toString(Calendar date) {
        return date.get(Calendar.YEAR)+"년 "+ (date.get(Calendar.MONTH)+1) 
                            +"월 " + date.get(Calendar.DATE) + "일 ";
    }
}

/*
출력 결과

date1은 2019년 4월 29일 월요일이고,
오늘(date2)은 2022년 2월 22일 화요일입니다.
그 날(date1)부터 지금(date2)까지 88992000초가 지났습니다.
일(day)로 계산하면 1030일입니다.

*/

 

날짜와 시간을 원하는 값으로 변경하려면 set메서드를 사용하면 된다.

void set(int Field, int value)
void set(int year, int month, int date)
void set(int year, int month, int date, int hourOfDay, int minute)
void set(int year, int month, int date, int hourOfDay, int minute, int second)

Calendar 예제3

두 개의 시간 데이터로부터 초 단위로 차이를 구한 다음, 시분초로 바꿔 출력하는 예제이다.

import java.util.*;

class Ex10_3 {
    public static void main(String[] args) {
        final int[] TIME_UNIT = {3600, 60, 1}; // 큰 단위를 앞에 놓는다.
        final String[] TIME_UNIT_NAME = {"시간 ", "분 ", "초 "};

        Calendar time1 = Calendar.getInstance();
        Calendar time2 = Calendar.getInstance();

        time1.set(Calendar.HOUR_OF_DAY, 10); // time1을 10시 20분 30초로 설정
        time1.set(Calendar.MINUTE, 20);
        time1.set(Calendar.SECOND, 30);

        time2.set(Calendar.HOUR_OF_DAY, 20); // time2을 20시 30분 10초로 설정
        time2.set(Calendar.MINUTE, 30);
        time2.set(Calendar.SECOND, 10);

        System.out.println("time1 :"+time1.get(Calendar.HOUR_OF_DAY)+"시 "
        +time1.get(Calendar.MINUTE)+"분 "+time1.get(Calendar.SECOND)+"초");
        System.out.println("time2 :"+time2.get(Calendar.HOUR_OF_DAY)+"시 "
        +time2.get(Calendar.MINUTE)+"분 "+time2.get(Calendar.SECOND)+"초");

        long difference = 
        Math.abs(time2.getTimeInMillis() - time1.getTimeInMillis())/1000;
        System.out.println("time1과 time2의 차이는 "+ difference +"초 입니다.");

        String tmp = "";
        for(int i=0; i < TIME_UNIT.length;i++) { 
              tmp += difference/TIME_UNIT[i] + TIME_UNIT_NAME[i]; 
              difference %= TIME_UNIT[i];
        } 
        System.out.println("시분초로 변환하면 " + tmp + "입니다.");
    }
}

/*
출력 결과

time1 :10시 20분 30초
time2 :20시 30분 10초
time1과 time2의 차이는 36580초 입니다.
시분초로 변환하면 10시간 9분 40초 입니다.
*/

Calendar 예제4

add(int field, int amount)를 사용하면 지정한 필드의 값을 원하는 만큼 증가 또는 감소시킬 수 있기 때문에 add메서드를 이용하면 특정 날짜 또는 시간을 기점으로 해서 일정시간 전후의 날짜와 시간을 알아낼 수 있다.

 

roll(int field, int amount)도 지정한 필드의 값을 증가 또는 감소시킬 수 있는데, add 메서드와의 차이점은 다른 필드에 영향을 미치지 않는다는 것이다.

import java.util.*;

class Ex10_4 {
    public static void main(String[] args) {
        Calendar date = Calendar.getInstance();
        date.set(2019, 7, 31);    // 2019년 8월 31일

        System.out.println(toString(date));
        System.out.println("= 1일 후 =");
        date.add(Calendar.DATE, 1);
        System.out.println(toString(date));

        System.out.println("= 6달 전 =");
        date.add(Calendar.MONTH, -6);
        System.out.println(toString(date));

        System.out.println("= 31일 후(roll) =");
        date.roll(Calendar.DATE, 31);
        System.out.println(toString(date));

        System.out.println("= 31일 후(add) =");
        date.add(Calendar.DATE, 31);
        System.out.println(toString(date));
    }

    public static String toString(Calendar date) {
        return date.get(Calendar.YEAR)+"년 "+ (date.get(Calendar.MONTH)+1) 
                   +"월 " + date.get(Calendar.DATE) + "일";
    }
}

/*
출력 결과

2019년 8월 31일
= 1일 후 =
2019년 9월 1일
= 6달 전 =
2019년 3월 1일
= 31일 후(roll) =
2019년 3월 1일
= 31일 후(add) =
2019년 4월 1일

*/

Calendar 예제5

달력을 출력하는 예제.

 

다음 달의 1일에서 하루를 빼면 이번 달의 마지막 일을 알 수 있다.

getActualMaximum(Calendar.Date)를 사용해도 해당 월의 마지막 날을 알 수 있다.

import java.util.*; 

class Ex10_5 { 
    public static void main(String[] args) { 
        if(args.length !=2) { 
            System.out.println("Usage : java Ex10_5 2019 9"); 
            return; 
        } 
        int year  = Integer.parseInt(args[0]); 
        int month = Integer.parseInt(args[1]); 
        int START_DAY_OF_WEEK = 0; 
        int END_DAY = 0; 

        Calendar sDay = Calendar.getInstance(); // 시작일 
        Calendar eDay = Calendar.getInstance(); // 끝일 

        // 월의 경우 0부터 11까지의 값을 가지므로 1을 빼주어야 한다. 
        // 예를 들어, 2019년 11월 1일은 sDay.set(2019, 10, 1);과 같이 해줘야 한다. 
          sDay.set(year, month-1, 1);       
        eDay.set(year, month, 1); 

        // 다음달의 첫날(12월 1일)에서 하루를 빼면 현재달의 마지막 날(11월 30일)이 된다. 
        eDay.add(Calendar.DATE, -1);       

        // 첫 번째 요일이 무슨 요일인지 알아낸다. 
        START_DAY_OF_WEEK = sDay.get(Calendar.DAY_OF_WEEK); 

        // eDay에 지정된 날짜를 얻어온다. 
        END_DAY = eDay.get(Calendar.DATE); 

        System.out.println("      " + args[0] +"년 " + args[1] +"월"); 
        System.out.println(" SU MO TU WE TH FR SA"); 

        // 해당 월의 1일이 어느 요일인지에 따라서 공백을 출력한다. 
        // 만일 1일이 수요일이라면 공백을 세 번 찍는다.(일요일부터 시작) 
        for(int i=1; i < START_DAY_OF_WEEK; i++)  
            System.out.print("   "); 

        for(int i=1, n=START_DAY_OF_WEEK ; i <= END_DAY; i++, n++) { 
            System.out.print((i < 10)? "  "+i : " "+i ); 
            if(n%7==0) System.out.println(); 
        } 
    } 
}

/*
출력 결과

>java Ex10_5 2019 9
            2019년 9월
 SU MO TU WE TH FR SA
  1  2  3  4  5  6  7
  8  9 10 11 12 13 14
 15 16 17 18 19 20 21
 22 23 24 25 26 27 28
 29 30

*/

Date와 Calendar간의 변환

Calendar를 Date로 변환

Calendar cal = Calendar.getInstance();
...
Date d = new Date(cal.getTimeInMillis()); //Date(long date)

 

Date를 Calendar로 변환

Calendar cal = Calendar.getInstance();
...
Date d = new Date(cal.getTimeInMillis()); //Date(long date)

 

형식화 클래스

형식화 클래스는 숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현할 수 있는 방법을 객체지향적으로 설계하여 표준화한 클래스

 

데이터를 정의된 패턴에 맞춰 형식화 할 수 있을 뿐만 아니라 형식화된 데이터에서 원래의 데이터를 얻어낼 수도 있다.

DecimalFormat

DecimalFormat은 숫자를 형식화하기 위해 사용되며, 숫자 데이터를 정수, 부동소수점, 금액 등의 다양한 형식으로 표현할 수 있으며, 일정한 형식의 텍스트 데이터를 숫자로 변환할 수 있도록 한다.

DecimalFormat 예제1

import java.text.*;

class Ex10_6 {
    public static void main(String[] args) throws Exception {
        double number  = 1234567.89;
        String[] pattern = {
            "0",
            "#",
            "0.0",
            "#.#",
            "0000000000.0000",
            "##########.####",
            "#.#-",
            "-#.#",
            "#,###.##",
            "#,####.##",
            "#E0",
            "0E0",
            "##E0",
            "00E0",
            "####E0",
            "0000E0",
            "#.#E0",
            "0.0E0",
            "0.000000000E0",
            "00.00000000E0",
            "000.0000000E0",
            "#.#########E0",
            "##.########E0",
            "###.#######E0",
            "#,###.##+;#,###.##-",
            "#.#%",
            "#.#\u2030",
            "\u00A4 #,###",
            "'#'#,###",
            "''#,###",
        };

        for(int i=0; i < pattern.length; i++) {
            DecimalFormat df = new DecimalFormat(pattern[i]);
            System.out.printf("%19s : %s\n",pattern[i], df.format(number));
        }
    } // main
}

/*
출력 결과

                  0 : 1234568
                  # : 1234568
                0.0 : 1234567.9
                #.# : 1234567.9
    0000000000.0000 : 0001234567.8900
    ##########.#### : 1234567.89
               #.#- : 1234567.9-
               -#.# : -1234567.9
           #,###.## : 1,234,567.89
          #,####.## : 123,4567.89
                #E0 : .1E7
                0E0 : 1E6
               ##E0 : 1.2E6
               00E0 : 12E5
             ####E0 : 123.5E4
             0000E0 : 1235E3
              #.#E0 : 1.2E6
              0.0E0 : 1.2E6
      0.000000000E0 : 1.234567890E6
      00.00000000E0 : 12.34567890E5
      000.0000000E0 : 123.4567890E4
      #.#########E0 : 1.23456789E6
      ##.########E0 : 1.23456789E6
      ###.#######E0 : 1.23456789E6
#,###.##+;#,###.##- : 1,234,567.89+
               #.#% : 123456789%
               #.#‰ : 1234567890‰
            ¤ #,### : $ 1,234,568
           '#'#,### : #1,234,568
            ''#,### : '1,234,568

*/

DecimalFormat 예제2

패턴을 이용해서 숫자를 변환하는 예제

import java.text.*;

class Ex10_7 {
    public static void main(String[] args) {
        DecimalFormat df  = new DecimalFormat("#,###.##");
        DecimalFormat df2 = new DecimalFormat("#.###E0");

        try {
            Number num = df.parse("1,234,567.89");
            System.out.print("1,234,567.89" + " -> ");

            double d = num.doubleValue(); 
            System.out.print(d + " -> ");

            System.out.println(df2.format(num));
        } catch(Exception e) {}
    } // main
}

/*
출력 결과

1,234,567.89 -> 12345689 -> 1.235E6
*/

SimpleDateFormat

SimpleDateFormat을 통해 날짜와 시간을 다양한 형식으로 출력할 수 있다.

Date today = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

//오늘 날짜를 yyyy-MM-dd형태로 변환하여 반환한다.
String result = df.format(today);

SimpleDateFormat 예제1

import java.util.*;
import java.text.*;

class Ex10_8 {
    public static void main(String[] args) {
        Date today = new Date();

        SimpleDateFormat sdf1, sdf2, sdf3, sdf4;
        SimpleDateFormat sdf5, sdf6, sdf7, sdf8, sdf9;

        sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        //홑따옴표(')는 escape기호이기 때문에 패턴 내에서 홑따옴표를 표시하기 위해서는 
        //홑따옴표를 연속적으로 두 번 사용해야 한다.
        sdf2 = new SimpleDateFormat("''yy년 MMM dd일 E요일");
        sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        sdf4 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");

        sdf5 = new SimpleDateFormat("오늘은 올 해의 D번째 날입니다.");
        sdf6 = new SimpleDateFormat("오늘은 이 달의 d번째 날입니다.");
        sdf7 = new SimpleDateFormat("오늘은 올 해의 w번째 주입니다.");
        sdf8 = new SimpleDateFormat("오늘은 이 달의 W번째 주입니다.");
        sdf9 = new SimpleDateFormat("오늘은 이 달의 F번째 E요일입니다.");

        System.out.println(sdf1.format(today));    // format(Date d)
        System.out.println(sdf2.format(today));
        System.out.println(sdf3.format(today));
        System.out.println(sdf4.format(today));
        System.out.println();
        System.out.println(sdf5.format(today));
        System.out.println(sdf6.format(today));
        System.out.println(sdf7.format(today));
        System.out.println(sdf8.format(today));
        System.out.println(sdf9.format(today));
    }
}

/*
출력 결과

2022-02-22
'22년 Feb 22일 화요일
2022-02-22 11:27:36.011
2022-02-22 11:27:36 AM

오늘은 올 해의 53번째 날입니다.
오늘은 이 달의 22번째 날입니다.
오늘은 올 해의 9번째 주입니다.
오늘은 이 달의 4번째 주입니다.
오늘은 이 달의 4번째 화요일입니다.
****
*/

SimpleDateFormat 예제2

parse(String source)를 사용하여 날짜 데이터의 출력형식을 변환하는 방법을 보여주는 예제이다.

import java.util.*;
import java.text.*;

class Ex10_9 {
    public static void main(String[] args) {
        DateFormat df  = new SimpleDateFormat("yyyy년 MM월 dd일");
        DateFormat df2 = new SimpleDateFormat("yyyy/MM/dd");

        try {
            Date d = df.parse("2019년 11월 23일");
            System.out.println(df2.format(d));
        } catch(Exception e) {}
    } // main
}

/*
출력 결과

2019/11/23

*/

SimpleDateFormat 예제3

화면으로부터 날짜를 입력받아 계산 결과를 출력하는 예제이다.

while과 try-catch문을 이용해서 사용자가 올바른 형식으로 날짜를 입력할 때까지 반복해서 입력받도록 하였다.

import java.util.*;
import java.text.*;

class Ex10_10 {
    public static void main(String[] args) {
        String pattern = "yyyy/MM/dd"; 
        DateFormat df = new SimpleDateFormat(pattern);
        Scanner s = new Scanner(System.in);

        Date inDate = null;

        System.out.println("날짜를 " + pattern 
        + "의 형태로 입력해주세요.(입력예:2019/12/31)");
        while(s.hasNextLine()) {
            try {
                inDate = df.parse(s.nextLine());
                break;
            } catch(Exception e) {
                System.out.println("날짜를 " + pattern 
                + "의 형태로 다시 입력해주세요.(입력예:2019/12/31)");
            }
        } // while

        Calendar cal = Calendar.getInstance();
        cal.setTime(inDate);
        Calendar today = Calendar.getInstance();
        long day = (cal.getTimeInMillis()
        - today.getTimeInMillis())/(60*60*1000);
        System.out.println("입력하신 날짜는 현재와 "+ day +"시간 차이가 있습니다.");
    } // main
}

/*
출력 결과

C:\jd1.8\work\ch10>java Ex10_10
날짜를 yyyy/MM/dd의 형태로 입력해주세요.(입력예:2019/12/31)
asdfasdf
날짜를 yyyy/MM/dd의 형태로 다시 입력해주세요.(입력예:2019/12/31)
20191231
날짜를 yyyy/MM/dd의 형태로 다시 입력해주세요.(입력예:2019/12/31)
2019/12/31
입력하신 날짜는 현재와 3935시간 차이가 있습니다.

*/

'Java > 자바 기초' 카테고리의 다른 글

9. java.lang 패키지와 유용한 클래스  (0) 2022.03.14
8. 예외처리  (0) 2022.03.14
7. 객체지향 프로그래밍 II  (0) 2022.03.11
6. 객체지향 프로그래밍 I  (0) 2022.03.11
5. 배열  (0) 2022.03.11