Java Standard - 날짜와 시간 & 형식화
...
Calendar와 Date
발전 순서와 내용
- JDK 1.0 -
Date
: 빈약함 - JDK 1.1 -
Calendar
:Date
보완 했지만 몇가지 단점 존재 - JDK 1.8 - java.time 패키지 : 기존 단점들을 개선한 새로운 클래스들이 추가됨
마지막에 새로 추가된 java.time 패키지만 배우면 좋겠지만, Calendar와 Date가 20년 넘게 사용되어왔고, 지금도 계속해서 사용되고 있으므로 알고 있어야함
Calendar
- Calendar
- 추상 클래스, 메서드를 통해 완전히 구현된 클래스의 인스턴스를 얻어야함
- 구현 클래스 :
GregorianCalendar
와BuddhistCalendar
,BuddhistCalendar
은 태국만 사용 - Calendar의 static 메서드 getInstance()를 통해 구현된 인스턴스를 얻어야함
- 시스템의 국가와 지역설정을 확인해 태국 외에는
GregorianCalendar
의 인스턴스 반환
어떻게 이런 코드가 가능할까? (처음에 이해 안되서 정리해놓음)
1 2 3 4 5 6 7 8 9 10
public static Calendar getInstance(){ String 국가 = 시스템 설정에서 가져옴; String 지역설정 = 시스템 설정에서 가져옴; if(국가.equals("태국") && 지역설정.equals("태국")){ return new BuddhistCalendar(); // 태국 구현 클래스 }else{ return new GregorianCalendar(); // 태국 외의 구현 클래스 } }
new
가 아닌 메서드로 인스턴스 생성한 이유: 최소한의 변경으로 동작하기 위해서
만약
new
로 인스턴스를 생성했다면? 다른 종류의 인스턴스를 필요로 하는 경우(ex, 새로운 구현 클래스 추가 등) Application 코드(=Calendar
를 사용하는 코드) 를 수정해야함 메서드로 인스턴스를 생성한다면, 해당 메서드의 내용만 수정하면 됨! - 시스템의 국가와 지역설정을 확인해 태국 외에는
Calendar와 Date 간의 변환
Date클래스는 Calendar가 추가 되면서 대부분의 메서드가 deprecated
(=더이상 사용을 권장하지 않음) 되어 잘 사용되지 않지만, Date를 필요로하는 메서드가 있기 때문에 변환할 일이 생김
Calendar → Date
1 2
Calendar cal = Calendar.getInstance(); Date d = new Date(cal.getTimeInMills()); //Date(long date);
Date → Calendar
1 2 3
Date d = new Date(); Calendar cal = Calendar.getInstance(); cal.setTime(d);
메서드
getInstance()
: 현재 시스템의 날짜와 시간 정보를 담고 있음get()
: 매개변수로 사용되는 int는 Calendar에 정의된 static상수를의미set()
: 날짜와 시간을 원하는 값으로 변경clear()
: 모든 필드의 값을 지정된 값으로 초기화getActualMaxium()
: 매개변수로 들어온 필드의 최대값을 알 수 있음- 증가와 감소
add()
: 지정한 필드값을 원하는 만큼 증가 또는 감소- 다른 필드에 영향을 미침 =
일
필드가 말일(end of month)에서 +1 →월
필드: 증가
- 다른 필드에 영향을 미침 =
roll()
: 지정한 필드값을 원하는 만큼 증가 또는 감소- 다른 필드에 영향을 미치지 않음 =
일
필드가 말일(end of month)에서 +1 →월
필드: 증가 안함 - 예외:
일
필드가 말일(end of month)에서월
필드의 값 변경시,일
필드에 영향
- 다른 필드에 영향을 미치지 않음 =
날짜의 계산
- 차이: 두 날짜를 최소단위인 초단위로 변경 → 차이를 구함 → 단위변경(큰 단위부터)
- 시간상의 전후 비교
after()
before()
을 사용- 두 날의 차이가 양수인지 음수인지 비교
형식화 클래스
- 특징
- 숫자, 날짜, 텍스트를 일정한 형식에 맞춰 표현할 수 있는 방법을 객체지향적으로 설계해 표준화
- 형식화에 사용될 패턴을 정의함
활용
- 데이터를 형식화
- 형식화된 데이터에서 원본 데이터 추출
DecimalFormat
특징
- 숫자를 형식화 하는데 사용, 다양한 형식(정수, 부동소수점, 금액 등)
일정한 형식을 가진 텍스트 → 숫자로 변환
Integer와 같은 Wrapper 클래스는 구분자가 있으면 변환하지 못함
사용하는 방법
형식화: 패턴을 작성해 인스턴스 생성 → 인스턴스의
format()
호출1 2 3 4
double number = 1234567.89; DecimalFormat df = new DecimalFormat("#.#E0"); //패턴을 작성해 인스턴스 생성 String result = df.format(number);//format() 호출
데이터 변환: 패턴을 작성해 인스턴스 생성 → 인스턴스의
parse()
호출1 2 3
DecimalFormat df = new DecimalFormat("#.#E0"); //패턴을 작성해 인스턴스 생성 Number num = df.parse("1234567.89");//parse() 호출 double d = num.doubleValue();//형변환
Number 클래스: Interger, Double과 같은 숫자를 저장하는 래퍼 클래스의 조상
SimpleDateFormat
- 특징
- Date와 Calendar만으로는 날짜데이터를 원하는 형식으로 다양하게 출력하는것은 복잡 → 날짜 데이터를 원하는 형식으로 다룰 수 있게 해줌
- DateFormat은 추상클래스, static 메서드인
getInstance()
를 이용해 구현체인 SimpleDateFormat을 얻어야함 - DateFormat은 추상클래스, static 메서드인
사용하는 방법
형식화: 패턴을 작성해 인스턴스 생성 → 인스턴스의
format()
호출1 2 3 4
Date today = new Date(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); //패턴을 작성해 인스턴스 생성 String result = df.format(today);//format() 호출
Date인스턴스만
format()
에 사용될 수 있어서 Calendar는 Date로 변환한뒤 호출데이터 변환: 패턴을 작성해 인스턴스 생성 → 인스턴스의
parse()
호출1 2 3 4 5 6 7 8
String strDate = "2015/02/15" Date inDate = null; SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd"); //패턴을 작성해 인스턴스 생성 try{ inDate = df.parse(strDate);//parse() 호출 }catch(ParseException e){ // strDate가 지정패턴으로 입력되지 않은경우 오류 발생 }
ChoiceFormat
특징
- 특정 범위에 속하는 값을 문자열로 변환
- 연속적 또는 불연속적인 범위의 값을 처리 → if나 switch문은 적절하지 못할 때가 있음
패턴
#
: 경계를 포함시킴<
: 경계를 포함시키지 않음
사용하는 방법
형식화: 패턴을 작성해 인스턴스 생성 → 인스턴스의
format()
호출1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int[] data = {91, 90, 80, 88, 70, 52, 60}; ChoiceFormat form = new ChoiceFormat("60#D|70#C|80<B|90#A"); for(int score: data){ System.out.println(data[i] + ":" +form.format(data[i])); } //결과 91:A 90:A 80:C// #이 아니라 <로해서 80은 B에 포함되지 않음 88:B 70:C 52:D 60:D
MessageFormat
특징
- 데이터를 정해진 양식에 맞게 출력 = 데이터가 들어갈 자리를 마련해 놓은 양식을 미리 작성후 데이터를 넣어 출력
- 지정된 양식에서 데이터를 추출
패턴 {0}
{1}
과같이 숫자로 표현된 곳이 데이터가 출력될 자리, 여러번 사용할 수 있음
- 객체배열이기 때문에 String 외에도 다른 객체들이 지정될 수 있음
사용하는 방법
형식화: 패턴을 작성해 인스턴스 생성 → 인스턴스의
format()
호출1 2
Object[] data = {"공수정", "여자", 26}; MessageFormat mf = MessageFormat.format("이름:{0}, 성별:{1}, 나이:{2}", data);
데이터 변환: 패턴을 작성해 인스턴스 생성 → 인스턴스의
parse()
호출1 2 3
String data = "이름:공수정, 성별:여자, 나이:26살" MessageFormat mf = MessageFormat.format("이름:{0}, 성별:{1}, 나이:{2}살"); Object[] parseData = mf.parse(data);
Object[]로 리턴
java.time 패키지
- java.time패키지와 서브 패키지들
- java.time: 날짜와 시간을 다루는데 필요한 핵심 클래스를 제공
- java.time.chrono: 표준이 아닌 달력 시스템을 위한 클래스 제공
- java.time.format: 날짜와 시간을 파싱하고, 형식화하기 위한 클래스 제공
- java.time.temporal: 날짜와 시간을 필드와 단위를 위한 클래스 제공
- java.time.zone: 시간대와 관련된 클래스 제공
- 특징
- 불변으로 다뤄짐 → 항상 새로운 객체를 반환
- 기존 Calendar는 값이 변경됨
- 불변으로 다뤄짐 → 항상 새로운 객체를 반환
java.time 패키지의 핵심 클래스
Calendar에서는 날짜와 시간을 따로 다루지만, java.time패키지에서는 날짜와 시간을 별도의 클래스로 분리
객체 생성
now()
: 현재 날짜와 시간을 저장하는 클래스 생성of()
: 해당 필드 값을 순서대로 지정해주면, 설정값대로 생성
시간과 관련된 인터페이스
- Temporal, TemporalAccessor, TemporalAdjuster: 날짜, 시간을 표현한 클래스들이 구현한 인터페이스
- TemporalAmount: 날짜, 시간의 차이(Period, Duration)의 표현한 클래스들이 구현한 인터페이스
- TemporalUnit: 날짜, 시간의 단위를 정의한 인터페이스
- ChronoUnit: TemporalUnit인터페이스를 구현한 것, 열거형
- TemporalField: 날짜와 시간의 필드를 정의한 인터페이스
- ChronoField: TemporalField인터페이스를 구현한 것
메서드
get()
: 특정 필드의 값을 얻음plus()
: 지정된 단위의 값을 더함minus()
: 지정된 단위의 값을 뺌
LocalDate와 LocalTime
가장 기본이 되는 클래스
생성방법
now()
: static 메서드, 현재 날짜와 시간을 저장하는 클래스 생성of()
: static 메서드, 해당 필드 값을 순서대로 지정해주면, 설정값대로 생성, 여러 버전으로 오버라이딩 되어있음parse()
: 문자열을 날짜와 시간으로 변환 할 수 있음
메서드
- 값을 조회
get()
: 특정 필드의 값을 가져옴
- 값 변경: 연산시마다 항상 새로운 객체를 생성해서 반환(=대입 연산자를 꼭 사용해야함)
with()
: 특정 필드의 값을 변경plus()
: 특정 필드의 값을 더함minus()
: 특정 필드의 값을 뺌truncatedTo()
: 지정된 것보다 작은 단위의 필드를 0으로 설정
- 비교: 두 날짜를 비교함
isAfter()
: 이후isBefore()
: 이전isEquals()
: 연표가 다른 두 날짜를 비교, ex 음력과 양력의 비교conpareTo()
: 날짜를 비교하는 메서드, 이전, 이후, 같음 을 알려줌 (int)
Instant
에포크 타임부터 경과된 시간을 나노초로 표현
시간을 초 단위와 나노초 단위로 나누어 저장
- 에포크타임
- 1970-01-01 00:00:00 UTC부터 경과된 시간
- UNIX의 시간이라고 하기도 함
특징
- 항상 UTC(+00:00)을 기준으로 함 → 시간대를 고려해야하는 경우, OffsetDateTime을 사용하는 것이 더 나은 선택일 수 있음
생성
now()
: 현재 날짜와 시간을 저장하는 클래스 생성ofEpochSecond()
: 설정값대로 생성
메서드
- 값을 조회
getEpochSecond()
: 초단위의 조회getNano()
: 나노초 단위의 조회
- 변환
static Date from(Instant instant)
: Instant → DateInstant toInstant()
: Date → Instant
LocalDateTime과 ZoneDateTime
- LocalDateTime: 날짜와 시간이 같이 있는 클래스
- ZoneDateTime: 날짜와 시간과 시간대까지 있는 클래스
생성
- LocalDateTime
- LocalDate + LocalTime
LocalDateTime.of()
: LocalDate와 LocalTime의 인스턴스를 매개변수로 해 생성of()
: LocalDate의 인스턴스나 LocalTime의 인스턴스에서 of메서드를 사용해 생성
now()
: 현재 날짜와 시간을 저장하는 클래스 생성of()
: 설정값대로 생성
- LocalDate + LocalTime
- ZoneDateTime
atZone()
: LocalDateTime인스턴스에서 사용, 시간대를 추가해 생성
변환
toLocalDate()
: LocalDateTime ->LocalDatetoLocalTime()
: LocalDateTime ->LocalTime
ZoneDateTime과 OffsetDateTime
시간대까지 가지고있는 클래스
- ZoneDateTime: 시간대를
ZoneId
로 표현 → 시간대를 시간의 차이로만 구분= 위험함 - OffsetDateTime: 시간대를
OffsetDateTime
으로 표현 → 아무런 변화 없이 일관된 시계체계를 유지 = 안전함OffsetDateTime
: UTC로부터 얼마나 떨어져있는지를 표현
TemporalAdjusters
자주쓰일만한 날짜계산들을 대신해주는 메서드를 정의해놓은 클래스
직접 구현하기
보통은 정의되어있는 메서드로 충분하겠지만, 필요하면 자주 사용되는 메서드를 직접 만들 수 있다.
TemporalAdjuster인터페이스를 구현한 클래스의 객체를 매개변수로 제공해야한다.
@FunctionalInterface? 함수형 인터페이스, 추상 메서드가 딱 하나만 존재하는 인터페이스 람다식과 관련된 것 같음 → 람다 단원에서 다시 학습해보자!
Period와 Duration
날짜와 시간의 간격을 표현하기 위한 클래스
- Period: 두 날짜간의 차이
- Duraion: 두 시간의 차이
메서드
- 차이 계산
between()
: static 메서드, 두 날짜와 시간의 차이를 구하는 함수- 양수와 음수,0의 결과값으로 이전, 이후, 같음을 알 수 있음
until()
: 인스턴스 메서드, 두 날짜와 시간의 차이를 구하는 함수
- 생성
of()
: 설정값대로 생성
- 변경
with()
: 특정 필드의 값을 변경minus()
: 빼기plus()
: 더하기multipledBy()
: 곱하기
- 조회
get()
: 특정 필드의 값을 가져옴- Period는 연도, 월, 일 필드값을 가져올 수 있고, Duration은 초와 밀리초 필드값을 가져옴
- 확인
isNegative()
: 음수인지 확인isZero()
: 0인지 확인
- 단위 변환
to~()
: 다른 단위의 값으로 변환하는데 사용
파싱과 포맷
특징
- format패키지 중 가장 핵심이 되는 클래스
- 다양한 형식들을 기본적으로 정의, 이외의 형식은 정의해서 사용할 수 있음
사용하는 방법
형식화: 패턴을 작성해 인스턴스 생성 → 인스턴스를 매개변수로 이용하는
format()
호출1 2 3 4
ZonedDateTime today = ZonedDateTime.now(); DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd"); //패턴을 작성해 인스턴스 생성 String result = today.format(df);//format() 호출
데이터 변환: 패턴을 작성해 인스턴스 생성 → 인스턴스를 매개변수로 하는
parse()
호출1 2
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy/MM/dd"); //패턴을 작성해 인스턴스 생성 LocalDate newDate = LocalDate.parse("2015/02/15", df);//parse()호출