[Ch12] 새로운 날짜와 시간 API
java.util.Date
클래스로 날짜와 시간 관련 기능을 쓸 수 있었다. 하지만 Date
클래스는 불변 클래스가 아니라서 안전하지 않다 (이펙티브 자바 CH10 참고) 또한 DateFormat
도 불변 클래스가 아니라 스레드 safe 하지 않다 실제로 마주쳤던 에러
따라서 java8 에는 java.time
패키지에 Joda-Time 의 많은 기능으로 추가해서 이와 같은 문제를 해결했다.
이 장에서는 새로운 날짜와 시간 API가 제공하는 새로운 기능을 살펴본다.
LocalDate, LocalTime, Instant, Duration, Period 클래스
- LocalDate : 시간을 제외한 날짜를 표현하는 불변 객체
LocalDate date = LocalDate.of(2021, 10, 25); System.out.println(date); // 2021-10-25 int year = date.getYear(); Month mongth = date.getMonth(); int day = date.getDayOfMonth();
- get 메서드에
TemporalField
를 전달해서 정보를 얻을 수도 있다.// LocalDate 의 get 메서드 @Override // override for Javadoc and performance public int get(TemporalField field) { if (field instanceof ChronoField) { return get0(field); } return ChronoLocalDate.super.get(field); } // 사용법 int year = date.get(ChronoField.YEAR); int month = date.get(ChronoField.MONTH_OF_YEAR);
- get 메서드에
- LocalTime : 날짜를 제외한 시간 을 표현하는 불변 객체
- LocalDateTime : 날짜와 시간을 모두 표현할 수 있다.
- Instant : 기계의 날짜 시간
- 나노초(10억분의 1초)의 정밀도를 제공한다
Instant.ofEpochSecond(3); Instant.ofEpochSecond(2, 1_000_000_000); // 2초 이후의 1억 나노초
- Instant 는 기계 전용의 유틸리티이기 때문에, 사람이 읽을 수 있는 시간정보를 제공하지 않는다.
- 나노초(10억분의 1초)의 정밀도를 제공한다
- Duration : 두 시간 객체 사이의 지속시간. 초와 나노초로 시간단위를 표현하므로 between 메서드에
LocalDate
를 전달할 수 없다 (Period 클래스를 사용한다.)LocalTime time1 = LocalTime.of(12, 00, 00); LocalTime time2 = LocalTime.of(12, 30, 00); Duration duration = Duration.between(time1, time2); System.out.println(duration); // PT30M System.out.println(duration.getSeconds()); // 1,800
지금까지 살펴본 TemporalField 인터페이스를 구현한 객체들은 모두 불변이다. 불변 클래스는 함수형 프로그래밍 그리고 스레드 안전성과 도메인 모델의 일관성을 유지하는 데 좋은 특징이다. 하지만 날짜/시간에 연산을 해야할 경우 객체의 값을 바꿔야 할 수도 있다. 자바8의 새로운 API 는 그런 기능도 제공한다.
날짜 조정, 파싱, 포매팅
withAttribute
메서드로 기존의 LocalDate
를 바꾼 버전을 간단하게 만들 수 있다. 바뀐 속성을 포함하는 새로운 객체를 반환하므로 여전히 불변 클래스이다.
public static void changeLocalDateTime() {
LocalDate date = LocalDate.of(2021, 10, 25);
LocalDate date1 = date.withYear(2020); // 2020-10-25
LocalDate date2 = date.withDayOfMonth(2); // 2021-10-02
LocalDate date3 = date.with(ChronoField.YEAR, 2019); // 2019-10-25
}
plusWeeks
, minusYears
등 명시적으로 연산을 하는 방법도 있다. 이들 메서드를 살펴보면 return new LocalDate
로 항상 새로운 객체를 반환해서, 기존의 객체는 수정/변경 하지 않는 것을 확인할 수 있다.
TemporalAdjusters 사용하기
조금 더 복잡한 날짜 조정이 필요하다면 with
메서드에 TemporalAdjusters
를 전달하는 방법으로 문제를 해결할 수 있다.
댓글남기기