본문 바로가기
Study/JAVA

[Java] 10-1, 2. 날짜와 시간 & 형식화

by jeongwle 2022. 9. 16.
728x90
반응형

 

날짜와 시간

1. Calendar와 Date

Date는 날짜와 시간을 다룰 목적으로 JDK1.0부터 제공되어온 클래스이다. 그리고 JDK1.1부터 Calendar 클래스를 제공하기 시작했다. JDK1.8에는 java.time패키지가 존재하지만 수십 년 간 사용되었고 현재도 사용되고 있기 때문에 Calendar와 Date클래스를 배워야 한다. 가볍게 배워보자

Calendar와 GregorianCalendar
Calendar는 추상클래스이다. Calendar를 상속받아 구현한 클래스로 GregorianCalendar와 BuddhistCalendar가 있다. 시스템의 국가와 지역설정을 확인해서 태국인 경우 후자의 인스턴스를 반환하고 나머지는 전자의 인스턴스를 반환한다.

// 비추천
class MyApplication {
  public static void main(String args[]) {
    Calendar cal = new GregorianCalendar(); // 경우에 따라 이부분 변경해야함
  }
}

// 추천
class MyApplication {
  public static void main(String args[]) {
    Calendar cal = Calendar.getInstance();
  }
}​

직접 생성해서 사용하지 않고 메서드를 통해 인스턴스를 반환받게 하는 이유는 최소한의 변경으로 프로그램이 동작할 수 있도록 하기 위함이다. 새로운 역법이 추가된다 하더라도 MyApplication을 변경하지 않고 getInstance()를 고치면 되기 때문이다.

Date와 Calendar
Calendar가 추가되면서 Date의 대부분의 메서드는 deprecated(더 이상 사용되지 않는)되었다. 그래도 여전히 Date를 필요로 하는 메서드들이 있기 때문에 Calendar를 Date로 또는 그 반대로 변환하는 법을 살펴보자.

1. Calendar를 Date로 변환
   Calendar cal = Calendar.getInstance();
   
   Date d = new Date(cal.getTimeInMillis());
   
2. Date를 Calendar로 변환
   Date d = new Date();
   Calendar cal = Calendar.getInstance();
   cal.setTime(d);​


getInstance()를 통해서 얻은 인스턴스는 기본적으로 현재 시스템의 날짜와 시간에 대한 정보를 담고 있다. 원하는 날짜나 시간으로 설정하려면 set 메서드를 사용하면 된다.

void set(int field, int value)
void set(int field, int month, int date)
void set(int field, int month, int date, int hourOfDay, int minute)
void set(int field, int month, int date, int hourOfDay, int minute, int second)​

지정한 필드의 값을 원하는 만큼 증가 또는 감소시킬 수 있다.

add(int field, int amount)
roll(int field, int amount)​

두 메서드의 차이점은 add메서드는 날짜필드(Calendar.DATE)의 값을 31만큼 증가시켰다면 다음 달로 넘어가기 때문에 월 필드(Calendar.MONTH)의 값도 1 증가하지만, roll 메서드는 월 필드의 값은 변하지 않고 일 필드의 값만 바뀐다. 다만 일 필드가 말일 일 경우 roll 메서드를 이용해서 월 필드를 변경하면 일 필드에 영향을 미칠 수 있다. 책에 여러 예제가 있으니 잘 살펴보자.

 

형식화 클래스

java.text패키지에 포함된 클래스로 숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현할 수 있다. 형식화 클래스는 형식화에 사용될 패턴을 정의하고 데이터를 정의된 패턴에 맞춰 형식화할 수 있을 뿐만 아니라 형식화된 데이터에서 원래의 데이터를 얻어낼 수도 있다.

 

1. DecimalFormat

숫자를 형식화 하는데 사용되는 것이 DecimalFormat이다. Decimal Format을 사용하면 숫자 데이터를 정수, 부동소수점, 금액 등의 다양한 형식으로 표현이 가능하다. 반대로 일정한 형식의 텍스트 데이터를 숫자로 쉽게 변환할 수도 있다. 자주 사용되는 패턴을 살펴보자.

기호 의미 패턴 결과(1234567.89)
 0  10진수(값이 없으면 0)  0
 0.0
 0000000000.0000
 1234568
 1234567.9
 0001234567.8900
 #  10진수  #
 #.#
 ##########.####
 1234568
 1234567.9
 1234567.89
 .  소수점  #.#  1234567.9
 -  음수부호  #.#-
 -#.#
 1234567.9-
 -1234567.9
 ,  단위 구분자  #,###.##
 #,####.##
 1,234,567.89
 123,4567.89
 E  지수기호  #E0
 0E0
 ##E0
 00E0
 ####E0
 0000E0
 #.#E0
 0.0E0
 0.000000000E0
 00.00000000E0
 000.0000000E0
 #.#########E0
 ##.########E0
 ###.#######E0
 .1E7
 1E6
 1.2E6
 12E5
 123.5E4
 1235E3
 1.2E6
 1.2E6
 1.234567890E6
 12.34567890E5
 123.4567890E4
 1.23456789E6
 1.23456789E6
 1.23456789E6
 ;  패턴구분자  #,###.##+;#,###.##-  1,234,567.89+ (양수일 때)
 1,234,567.89- (음수일 때)
 %  퍼센트  #.#%  123456789%
 \u2030   퍼밀(퍼센트 x 10)  #.#\u2030  1234567890%
 \u00A4  통화  \u00A4 #,###  ₩ 1,234,568
 '  escape문자  '#'#,###
 ''#,###
 #1,234,568
 '1,234,568
뭔가 벌써 어지럽다.

DecimalFormat을 사용하는 방법은 간단하다. 원하는 출력형식의 패턴을 작성하여 DecimalFormat인스턴스를 생성한 후 출력하고자 하는 문자열로 format메서드를 호출하면 원하는 패턴에 맞게 변환된 문자열을 얻게 된다.

double number = 1234567.89;
DecimalFormat df = new DecimalFormat("#.#E0");
String result = df.format(number);​

 

2. SimpleDateFormat

Date와 Calendar를 계싼하는 방법만 배웠는데 이제는 출력하는 방법에 대해 배운다. Date와 Calendar 만으로 날짜 데이터를 원하는 형태로 출력하는 것은 불편하고 복잡하다. 하지만 SimpleDateFormat과 함께라면 간단히 해결된다고 한다.

기호 의미 보기
 G  연대(BC, AD)  AD
 y  년도  2006
 M  월(1 ~ 12 또는 1월 ~ 12월)  10 또는 10월, OCT
 w  년의 몇 번째 주(1 ~ 53)  50
 W  월의 몇 번째 주(1 ~ 5)  4
 D  년의 몇 번째 일(1 ~ 366)  100
 d  월의 몇 번째 일(1 ~ 31)  15
 F  월의 몇 번째 요일(1 ~ 5)  1
 E  요일  월
 a  오전 / 오후(AM, PM)  PM
 H  시간(0 ~ 23)  20
 k  시간(1 ~ 24)  13
 K  시간(0 ~ 11)  10
 h  시간(1 ~ 12)  11
 m   분(0 ~ 59)  35
 s  초(0 ~ 59)  55
 S  천분의 일초(0 ~ 999)  253
 z  Time zone(General time zone)  GMT+0:00
 Z  Time zone(RFC 822 time zone)  +0900
 '  escape문자(특수문자를 표현하는데 사용)  없음

... 뭔가 일관성과 연관성이 부족한 느낌이 든다. 하지만 나보다 똑똑한 사람들이 어련히 잘 만들었겠지..

SimpeDateFormat을 사용하는 방법은 간단하다. 1번에서 배운 것과 같다.

Date today = new Date();
SimpeDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String result = df.format(today);​

Date 인스턴스만 format메서드에 사용될 수 있기 때문에 Calendar 인스턴스는 Date 인스턴스로 변환한 후 사용하자.

 

3. ChoiceFormat

ChoiceFormat은 특정 범위에 속하는 값을 문자열로 변환해준다. 연속적 또는 불연속적 범위의 값들을 처리하는 데 있어서 if문이나 switch문은 적절하지 못한 경우가 많은데 ChoiceFormat을 사용하면 코드를 간단하고 직관적으로 만들 수 있다.

import java.text.ChoiceFormat;

public class ChoiceFormatEx1 {
    public static void main(String[] args) {
        /*
         낮은 값 부터 큰 값의 순서로 적어야 한다.
         limits와 grades간의 순서와 개수를 맞추어야 한다.
         */
        double[] limits = {60, 70, 80, 90};
        String[] grades = {"D", "C", "B", "A"};

        int[] scores = {100, 95, 88, 70, 52, 60, 70};

        ChoiceFormat form = new ChoiceFormat(limits, grades);

        for (int score : scores) {
            System.out.println(score + " : " + form.format(score));
        }
        /*
            100 : A
            95 : A
            88 : B
            70 : C
            52 : D
            60 : D
            70 : C
         */
    }
}​

경계값은 double형으로 반드시 모두 오름차순으로 정렬되어야 한다. 치환 될 문자열의 개수는 경계값에 의해 정의된 범위(60~69, 70~79, 80~89, 90~)의 개수와 일치해야 한다 그렇지 않을 경우 IllegalArgumentException이 발생한다.


import java.text.ChoiceFormat;

public class ChoiceFormatEx2 {
    public static void main(String[] args) {
        String pattern = "60#D|70#C|80<B|90#A";
        int[] scores = {91, 90, 80, 88, 80, 52, 60};

        ChoiceFormat form = new ChoiceFormat(pattern);

        for (int score : scores) {
            System.out.println(score + " : " + form.format(score));
        }
    }
    /*
        91 : A
        90 : A
        80 : C
        88 : B
        80 : C
        52 : D
        60 : D
     */
}​

위의 예제를 패턴을 사용하도록 변경한 것이다. 패턴은 구분자로 #, < 이 두 가지를 제공한다. #은 경계값을 범위에 포함시키지만 <는 포함시키지 않는다.

 

4. MessageFormat

MessageFormat은 데이터를 정해진 양식에 맞게 출력할 수 있도록 도와준다. 데이터가 들어갈 자리를 마련해 놓은 양식을 미리 작성하고 프로그램을 이용해서 다수의 데이터를 같은 양식으로 출력할 때 사용하면 좋다.

import java.text.MessageFormat;

public class MessageFormatEx1 {
    public static void main(String[] args) {
        String msg = "Name : {0} \nTel : {1} \nAge : {2} \nBirthday : {3}";

        Object[] arguments = {
                "이자바", "02-123-1234", "88", "13-13"
        };

        String result = MessageFormat.format(msg, arguments);
        System.out.println(result);
    }
    /*
        Name : 이자바 
        Tel : 02-123-1234 
        Age : 88 
        Birthday : 13-13
     */
}​

msg를 작성할 때 {숫자}로 표시된 부분이 데이터가 출력될 자리이다. 여기에 사용되는 숫자는 배열처럼 인덱스가 0부터 시작하고 양식에 들어갈 데이터는 객체배열인 arguments에 지정되어 있음을 알 수 있다.


import java.text.MessageFormat;

public class MessageFormatEx3 {
    public static void main(String[] args) throws Exception {
        String[] datas = {
                "INSERT INTO CUST_INFO VALUES ('이자바', '02-123-1234', 88, '13-13');",
                "INSERT INTO CUST_INFO VALUES ('김자바', '02-123-1235', 89, '14-14');",
        };

        String pattern = "INSERT INTO CUST_INFO VALUES ({0}, {1}, {2}, {3});";
        MessageFormat mf = new MessageFormat(pattern);

        for (String data : datas) {
            Object[] objs = mf.parse(data);
            for (Object obj : objs) {
                System.out.print(obj + ",");

            }
            System.out.println();
        }
        /*
            '이자바','02-123-1234',88,'13-13',
            '김자바','02-123-1235',89,'14-14',
         */
    }
}​

위의 예제는 parse(String source)를 이용해서 출력된 데이터로부터 필요한 데이터만을 뽑아내는 방법을 보여준다.
728x90
반응형

'Study > JAVA' 카테고리의 다른 글

[Java] 11. 컬렉션 프레임웍(1)  (2) 2022.09.27
[Java] 10-3. java.time 패키지  (2) 2022.09.19
[Java] 9-2. 유용한 클래스  (0) 2022.09.14
[Java] 9-1. java.lang패키지  (0) 2022.09.13
[Java] 8. 예외처리(exception handling)  (0) 2022.09.07

댓글