자바 도전기-16

김치전사·2022년 2월 14일
0

자바도전기

목록 보기
16/17

드디어 남궁성님의 자바의 정석 2권을 시작하게 되었다.

날짜와 시간

Calendar와 Date

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

Calendar cal = new Calendar();//에러! 추상클래스는 인스턴스를 생성할 수 없다
Calendar cal = Calendar.getInstance();//OK, getInstance()메서드는 Calendar 클래스를 구현한 클래스의 인스턴스를 반환한다

Calendar를 상속바다 완전히 구현한 클래스로는 GregorianCalendar와 BuddhistCalendar가 있는데 getInstance()는 시스템의 국가와 지역설정을 확인해서 태국인 경우에는 BuddhistCalendar의 인스턴스를 반환하고, 그 외에는 GregorianCalendar의 인스턴스를 반환한다
GregorianCalendar는 Calendar를 상속받아 오늘날 전세계 공통으로 사용하고 있는 그레고리력에 맞게 구현한 것으로 태국을 제외한 나머지 국가에서는 GregorianCalendar를 사용하면 된다.

1.Calendar를 Date로 변환

Calendar cal = Calendar.getInstance();
	...
Date d = new Date(cal.getTimeInMillis());//Date(long date)
  1. Date를 Calendar로 변환
Date d = new Date();
	...
Calendar cal = Calendar.getInstance();
cal.setTime(d)

날짜와 시간을 원하는 값으로 변경하려면 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)
import java.util.*;

public class CalendarCalcul {
    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.YEAR,2015);//2015년 4월 25일 14시 46분 33초로 설정
        time1.set(Calendar.MONTH,4);
        time1.set(Calendar.DATE,25);
        time1.set(Calendar.HOUR_OF_DAY,14);
        time1.set(Calendar.MINUTE,46);
        time1.set(Calendar.SECOND,33);

        time2.set(Calendar.YEAR,2021);//2021년 2월 7일 17시 58분 49초로 설정
        time2.set(Calendar.MONTH,2);
        time2.set(Calendar.DATE,7);
        time2.set(Calendar.HOUR_OF_DAY,17);
        time2.set(Calendar.MINUTE,58);
        time2.set(Calendar.SECOND,49);

        System.out.println("time1 :"+time1.get(Calendar.YEAR)+"년 "+time1.get(Calendar.MONTH)+"월 "+time1.get(Calendar.DATE)+"일 "+time1.get(Calendar.HOUR_OF_DAY)+"시 "+time1.get(Calendar.MINUTE)+"분 "+time1.get(Calendar.SECOND)+"초");
        System.out.println("time2 :"+time2.get(Calendar.YEAR)+"년 "+time2.get(Calendar.MONTH)+"월 "+time2.get(Calendar.DATE)+"일 "+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+"초 입니다.");
    }
}

형식화 클래스

형식화 클래스는 java.text패키지에 포함되어 있으며 숫자, 날짜, 텍스트 데이터를 일정한 형식에 맞게 표현할 수 있는 방법을 객체지향적으로 설계하여 표준화하였다.
형식화 클래스는 형식화에 사용될 패텬얼 정의하는데, 데이터를 정의된 패턴에 맞춰 형식화할 수 있을 뿐만 아니라 역으로 형식화된 데이터에서 원래의 데이터를 얻어낼 수도 있다.

DecimalFormat

형식화 클래스 중에서 숫자를 형식화 하는데 사용되는 것이 DecimalFormat이다
DecimalFormat을 이용하면 숫자 데이터를 정수, 부동소수점, 금액 등의 다양한 형식으로 표현할 수 있으며, 반대로 일정한 형식의 텍스트 데이터를 숫자로 쉽게 변환하는 것도 가능하다

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

double number = 1234567.89;
DecimalFormat df = new DecimalFormat("#.#E0");
String result = df.format(number);
import java.text.*;

public class DecimalFormatEx {
    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+" -> ");//1234567.89

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

parse메서드를 이용하면 기호와 문자가 포함된 문자열을 숫자로 쉽게 변환할 수 있다.
parse(String source)는 DecimalFormat의 조상인 NumberFormat에 정의된 메서드이며, 이 메서드의 선언부는 다음과 같다

public Number parse(String source) throws ParseException

Number클래스는 Integer, Double과 같은 숫자를 젖아하는 래퍼 클래스의 조상이며, doubleValue( )는 Number에 저장된 값을 double형의 값으로 변환하여 반환한다.

SimpleDateFormat

SingleDateFormat을 사용하면 날짜 데이터를 원하는 형태로 다양하게 출력할 수 있다.
SingleDateFormat은 먼저 원하는 출력형식의 패턴을 작성하여 SimpleDateFormat인스턴스를 생성한 다음, 출력하고자 하는 Date인스턴스를 가지고 format(Date d)를호출하면 지정한 출력형식에 맞게 변환된 문자열을 얻게 된다.

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

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

public class DateFormatEx {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        cal.set(2021,1,10);

        Date day = cal.getTime();//Calendar를 Date로 변환

        SimpleDateFormat sdf1, sdf2, sdf3, sdf4;
        sdf1 = new SimpleDateFormat("yyyy-MM-dd");
        sdf2 = new SimpleDateFormat("yy-MM-dd E요일");
        sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        sdf4 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");

        System.out.println(sdf1.format(day));//2021-02-10
        System.out.println(sdf2.format(day));//21-02-10 목요일
        System.out.println(sdf3.format(day));//2021-02-10 17:55:10.013
        System.out.println(sdf4.format(day));//2021-02-10 05:55:10 오후
    }
}

ChoiceFormat

ChoiceFormat은 특정 벙위에 속하는 값을 문자열로 변환해준다.
연속적 또는 불연속적인 범위의 값들을 처리하는 데 있어서 ChoiceFormat을 잘 사용하면 복잡하게 처리될 수밖에 없었던 코드를 간단하고 직관적으로 만들 수 있다.

import java.text.*;

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

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

        ChoiceFormat form = new ChoiceFormat(limits, grades);

        for(int i=0;i<scores.length;i++){
            System.out.println(scores[i]+":"+form.format(scores[i]));
        }
    }
}

예제에서는 4개의 경계갓에 의해 '60~69','70~79','80~89','90~'의 범위가 정의되었다.

MessageFormat

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

import java.text.*;

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

        Object[] arguments={
                "이자바","02-123-4567","27","02-08"
        };

        String result = MessageFormat.format(msg,arguments);
        System.out.println(result);
    }
}

MessageFormat에 사용할 양식인 문자열 msg를 작성할 때 '{숫자}'로 표시된 부분이 데이터가 출력될 자리이다.

java.time패키지

패키지설명
java.time날짜와 시간을 다루는데 필요한 핵심 클래스들을 제공
java.time.chrono표준(ISO)이 아닌 달력 시스템을 위한 클래스들을 제공
java.time.format날짜와 시간을 파싱하고, 형식화하기 위한 클래스들을 제공
java.time.temporal날짜와 시간의 필드(field)와 단위(unit)를 위한 클래스들을 제공
java.time.zone시간대(time-zone)와 관련된 클래스들을 제공

위의 패키지들에 속한 클래스들의 가장 큰 특징은 String클래스처럼 불변(immutable)이라는 것이다.

java.time패키지의 핵심 클래스

날짜와 시간을 하나로 표현하는 Calendar클래스와 달리, java.time패키지에서는 날짜와 시간을 별도의 클래스로 분리해 놓았다.
시간을 표현할 때는 LocalTime클래스를 사용하고, 날짜를 표현할 때는 LocalDate클래스를 사용한다.
날짜와 시간이 모두 필요할 때는 LocalDateTime클래스를 사용하면 된다.
시간대(time-zone)까지 다뤄야 한다면, ZonedDateTime클래스를 사용한다

Period와 Duration

날짜와 시간의 간격을 표현하기 위한 클래스도 있는데, Period는 두 날짜간의 차이를 표현하기 위한 것이고, Duration은 시간의 차이를 표현하기 위한 것이다.

객체 생성하기 - now( ), of( )

now( )는 현재 날짜와 시간을 저장하는 객체를 생성한다.

LocalDate date = LocalDate.now();//2022-02-11
LocalTime time = LocalTime.now();//17:32:03.154
LocalDateTime dateTime = LocalDateTime.now();//2022-02-11T17:32:03.154
ZonedDateTime dateTimeInKr = ZonedDateTime.now();

TemporalUnit과 TemporalField

날짜와 시간의단위를 정의해 놓은 것이 TemporalUnit인터페이스이고, 이 인터페이스를 구현한 것이 열거형 ChronoUnit이다.
TemporalField는 년, 월, 일 등 날짜와 시간의 필드를 정의해 놓은 것으로, 열거형 Chrono가 이 인터페이스를 구현했다.

LocalTime now = LocalTime.now();//현재 시간
int minute = now.getMinute();//현재 시간에서 분(minute)만 뽑아낸다.
int minute = now.get(ChronoField.MINUTE_OF_HOUR);//위의 문장과 동일

날짜와 시간에서 특정 필드의 값만을 얻을 때는 get()이나, get으로 시작하는 이름의 메서드를 이용한다.

LocalDate today = LocalDate.now();//오늘
LocalDate tomorrow = today.plus(1,ChronoUnit.DAYS);//오늘에 1일을 더한다
LocalDate tomorrow = today.plusDays(1);//위의 문장과 돌일
int get(TemporalField field)
LocalDate plus(long amountToAdd, TemporalUnit unit)

LocalDate와 LocalTime

LocalDate와 LocalTime은 java.time패키지의 가장 기본이 되는 클래스이며, 나머지 클래스들은 이들의 확장이므로 이 두 클래스만 잘 이해하고 나면 나머지는 아주 쉬워진다.
객체를 생성하는 방법은 현재의 날짜와 시간을 LocalDate와 LocalTime으로 각각 반환하는 now( )와 지정된 날짜와 시간으로 LocalDate와 LocalTime객체를 생성하는 of( )가 있다. 둘 다 static메서드이다.

LocalDate today = LocalDate.now();//오늘의 날짜
LocalTime now = LocalTime.now();//현재 시간

LocalDate birthDate = LocalDate.of(1999,12,31);//1999년 12월 31일
LocalTime birthDate = LocalTime.of(23,59,59);//23시 59분 59초

LocalDate birthDate = LocalDate.ofYearDay(1999,365);//1999년 12월 31일
LocalTime birthTime = Localtime.ofSecondDay(86399);//23시 59분 59초

필드의 값 변경하기 - with( ),plus( ),minus( )

날짜와 시간에서 특정 필드 값을 변경하려면, 다음과 같이 with로 시작하는 메서드를 사용하면 된다.

LocalDate with(TemporalField field, long newValue)

date = date.withYear(2000);//년도를 2000년으로 변경
time = time.withHour(12);//시간을 12시로 변경

날짜와 시간의 비교 - isAfter( ), isBefore( ), isEqual( )

LocalDate와 LocalTime도 compareTo( )가 적절히 오버라이딩되어 있어서, 아래와 같이 compareTo( )로 비교할 수 있다.

int result = date1.compareTo(date2);//같으면 0, date1이 이전이면 -1, 이후면 1

boolean isAfter(ChronoLocalDate other)
boolean isBoolean(ChronoLocalDate other)
boolean isEqual(ChronoLocalDate other) //LocalDate에만 있음

Instant

Instant는 에포크 타임부터 경과된 시간을 나노초 단위를 표현한다.

Instant now = Instant.now();
Instant now2 = Instant.ofEpochSecond(now.getEpochSecond());
Instant now3 = Instant.ofEpochSecond(now.getEpochSecond(), now.getNano());

long epochSec = now.getEpochSecond();
int nano = now.getNano();

Instant와 Date간의 변환

static Date from(Instant instant)//Instant->Date
Instant toInstant()//Date->Instant

LocalDateTime과 ZonedDateTime

LocalDate와 LocalTime을 합쳐 놓은 것이 LocalDateTime이고, LocalDateTime에 시간대(time zone)를 추가한 것이 ZoneDateTime이다.

LocalDateTime의 변환

LocalDateTime을 LocalDate 또는 LocalTime으로 변환할 수 있다

LocalDateTime dt = LocalDateTime.of(2022, 02, 14, 17, 30, 46);
LocalDate date = dt.toLocalDate();//LocalDateTime -> LocalDate
LocalTime time = dt.toLocalTime();//LocalDateTime -> LocalTime

LocalDateTime으로 ZonedDateTime 만들기

LocalDateTime에 시간대(time-zone)를 추가하면, ZonedDateTime이 된다
기존에는 TimeZone클래스로 시간대를 다뤘지만 새로운 시간 패키지에서는 ZoneId라는 클래스를 사용한다.
ZoneId는 일광 절약시간을 자동적으로 처리해준다
LocalDate에 시간 정보를 추가하는 atTime( )을 쓰면 LocalDateTime을 얻을 수 있는 것처럼, LocalDateTime에 atZone( )으로 시간대 정보를 추가하면, ZonedDateTime을 얻을 수 있다

ZoneId	zid = ZoneId.of("Asia/Seoul");
ZonedDateTime	zdt = dateTime.atZone(zid);

TemporalAdjusters

자주 쓰일만한 날짜 계산들을 대신 해주는 메서드를 정의해놓은 것이 TemporalAdjusters클래스이다

Period와 Duration

Period는 날짜의 차이를, Duration은 시간의 차이를 계산하기 위한 것이다.
예를 들어 두 날자 date1과 date2의 차이를 나타내는 Period는 between( )으로 얻을 수 있다.

LocalDate date1 = LocalDate.of(2014,5,4);
LocalDate date2 = LocalDate.of(2022,2,14);
Period pe = Period.between(date1, date2);

LocalTime time1 = LocalTime.of(00,00,00);
LocalTIme time2 = LocalTime.of(12,34,56);
Duration du = Duration.between(time1, time2);
profile
개인공부 블로그입니다. 상업적 용도 X

0개의 댓글