자바 인 액션 실전 요약
Ch 12. 새로운 날짜와 시간 API
주니어인 내가 당장 알아야하는 챕터만으로 정리했다.
병렬 처리와 프로그래밍의 역사적 흐름과 같은 내용은 제외했다.
최대한 책의 내용을 그대로 요약하려 노력했고 내 의견은 기울여서 표현했다.
예제 코드는 내 프로젝트에서 따오거나 직접 작성한 코드들이다.
Chapter 12
새로운 날짜와 시간 API
자바 8 이전 버전에서 제공하는 java.util.Date 클래스는 여러 결함이 존재했다.
java.time 패키지는
LocalDate, LocalTime, LocalDateTime, Instant, Duration, Period 와 같은 새로운 클래스를 제공한다.
다음은 LocalDate와 LocalTime의 간단한 예시이다.
LocalDate date = LocalDate.of(2017, 9, 21); // 2017년 9월 21일
int year = date.getYear(); // 2017년
DayOfWeek dow = date.getDayOfWeek(); // 목요일
boolean leap = date.isLeapYear(); // 윤년이 아니다.
LocalTime time = LocalTime.of(13, 45, 20); // 13:45:20
int hour = time.getHour(); // 13시
LocalDate date = LocalDate.parse("2017-09-21"); // 2017년 9월 21일
LocalTime time = LocalTime.parse("13:45:20");
LocalDateTime은 LocalDate와 LocalTime의 합이라고 생각하면 된다.
LocalDateTime dateTime1 = LocalDateTime.of(2017, Month.SEPTEMBER, 21, 13, 45, 20);
LocalDateTime dateTime2 = LocalDateTime.of(date, time);
LocalDateTime dateTime3 = date.atTime(13, 45, 20);
LocalDateTime dateTime4 = time.atDate(date);
Instant class
사람은 주, 날짜, 시간, 분으로 날짜와 시간을 계산한다.
하지만 기계는 연속된 시간에서 특정 지점을 하나의 큰 수로 표현하는 것이 자연스러운 시간 표현 방법이다.
java.time.Instant 클래스는 이와 같은 관점에서 시간을 표현한다.
유닉스 에포크 시간(Unix epoch time: 1970년 1월 1일 0시 0분 0초 UTC)를 기준으로 특정 지점까지의 시간을 초로 표현한다.
Instant 클래스는 나노초(10억분의 1초)의 정밀도를 제공한다.
예시
// 1970-01-01T00:00:03Z
Instant.ofEpochSecond(3)
Duration과 Period class
이번에는 두 시간 객체 사이의 지속시간을 만들어보자.
LocalTime time1 = LocalTime.of(13, 45, 20);
LocalTime time2 = LocalTime.of(14, 55, 20);
Duration duration = Duration.between(time1, time2);
Duration threeMinutes = Duration.ofMinutes(3);
Period period = Period.ofDays(10);
System.out.println(period);
System.out.println(duration);
System.out.println(threeMinutes);
// 위 출력 결과
// P10D
// PT1H10M
// PT3M
날짜와 시간 객체 출력과 파싱
날짜와 시간 관련 작업에 포매팅과 파싱은 서로 떨어질 수 없는 관계이다.
java.time.format.DateTimeFormatter 클래스를 살펴보면, 다음의 두 상수가 정의되어 있다.
public static final DateTimeFormatter ISO_LOCAL_DATE;
static {
ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
public static final DateTimeFormatter BASIC_ISO_DATE;
static {
BASIC_ISO_DATE = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendValue(YEAR, 4)
.appendValue(MONTH_OF_YEAR, 2)
.appendValue(DAY_OF_MONTH, 2)
.optionalStart()
.parseLenient()
.appendOffset("+HHMMss", "Z")
.parseStrict()
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
이 상수들을 활용하면 다음과 같다.
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(s1);
System.out.println(s2);
// 위 출력 결과
// 20140318
// 2014-03-18
가끔 사용한 적이 있는, 패턴에 맞게 날짜와 시간 출력하기는 다음과 같다.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
LocalDate date2 = LocalDate.parse(formattedDate, formatter);
System.out.println(date1);
System.out.println(formattedDate);
System.out.println(date2);
// 위 출력 결과
// 2014-03-18
// 18/03/2014
// 2014-03-18
시간대까지 저장하는 ZoneId, ZonedDateTime
우리는 서울, 도쿄와 같은 시간대를 설정하거나 서머타임(Daylight Saving Time, DST)을 처리해야할 수도 있다.
이러한 요소들을 처리할 수 있게 만들어주는 ZoneId와 ZonedDateTime에 대해서 알아보자.
표준 시간이 같은 지역을 묶어서 시간대 규칙 집합을 정의한다.
지역 ID는 '{지역}/{도시}' 형식으로 이루어 진다.
ZoneId romeZone = ZoneId.of("Europe/Rome");
ZoneId zoneId = TimeZone.getDefault().toZoneId();
System.out.println(romeZone);
System.out.println(zoneId);
// 위 출력 결과
// Europe/Rome
// Asia/Seoul
ZoneId는 LocalDate, LocalTime, LocalDateTime과 같이 ZonedDateTime 인스턴스로 변환할 수 있다.
LocalDate date = LocalDate.of(2014, 3, 18);
ZonedDateTime zonedDateTime1 = date.atStartOfDay(romeZone);
LocalDateTime localDateTime = LocalDateTime.of(2014, 3, 18, 14, 45);
ZonedDateTime zonedDateTime2 = localDateTime.atZone(romeZone);
System.out.println(zonedDateTime1);
System.out.println(zonedDateTime2);
// 위 출력 결과
// 2014-03-18T00:00+01:00[Europe/Rome]
// 2014-03-18T14:45+01:00[Europe/Rome]
앞서 나온 클래스들의 관계를 대략적으로 표현하면 다음과 같다.
추가 설명 요약
새로운 날짜, 시간 API는 모두 불변하다.
날짜와 시간 객체를 절대적인 방법과 상대적인 방법으로 처리할 수 있다.
기존 인스턴스를 변환하지 않도록 새로운 인스턴스가 생성된다.
'자바' 카테고리의 다른 글
코드 가독성 개선 with if kakao (0) | 2023.12.11 |
---|---|
JVM 메모리 구조을 알아보고 JVM warm up을 이해하자 (0) | 2023.12.07 |
자바 인 액션 실전 요약 (2) Ch. 3 람다 표현식 (0) | 2023.10.19 |
자바 인 액션 실전 요약 (1) Ch 1 ~ 2 자바와 동적 파라미터화 (1) | 2023.10.17 |